diff --git a/src/SharpCompress/Providers/CompressionProviderBase.cs b/src/SharpCompress/Providers/CompressionProviderBase.cs index 575cc95c..77ec72a5 100644 --- a/src/SharpCompress/Providers/CompressionProviderBase.cs +++ b/src/SharpCompress/Providers/CompressionProviderBase.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -31,17 +32,18 @@ public abstract class CompressionProviderBase : ICompressionProvider public abstract Stream CreateCompressStream(Stream destination, int compressionLevel); /// - public abstract Stream CreateCompressStream( + public virtual Stream CreateCompressStream( Stream destination, int compressionLevel, CompressionContext context - ); + ) => CreateCompressStream(destination, compressionLevel); /// public abstract Stream CreateDecompressStream(Stream source); /// - public abstract Stream CreateDecompressStream(Stream source, CompressionContext context); + public virtual Stream CreateDecompressStream(Stream source, CompressionContext context) => + CreateDecompressStream(source); /// /// Asynchronously creates a compression stream. @@ -68,8 +70,7 @@ public abstract class CompressionProviderBase : ICompressionProvider CancellationToken cancellationToken = default ) { - cancellationToken.ThrowIfCancellationRequested(); - return new ValueTask(CreateCompressStream(destination, compressionLevel, context)); + return CreateCompressStreamAsync(destination, compressionLevel, cancellationToken); } /// @@ -95,7 +96,34 @@ public abstract class CompressionProviderBase : ICompressionProvider CancellationToken cancellationToken = default ) { - cancellationToken.ThrowIfCancellationRequested(); - return new ValueTask(CreateDecompressStream(source, context)); + return CreateDecompressStreamAsync(source, cancellationToken); + } + + protected static void ValidateRequiredSizes(CompressionContext context, string algorithmName) + { + if (context.InputSize < 0 || context.OutputSize < 0) + { + throw new ArgumentException( + $"{algorithmName} decompression requires InputSize and OutputSize in CompressionContext.", + nameof(context) + ); + } + } + + protected static T RequireFormatOption( + CompressionContext context, + string algorithmName, + string optionName + ) + { + if (context.FormatOptions is not T options) + { + throw new ArgumentException( + $"{algorithmName} decompression requires {optionName} in CompressionContext.FormatOptions.", + nameof(context) + ); + } + + return options; } } diff --git a/src/SharpCompress/Providers/ContextRequiredDecompressionProviderBase.cs b/src/SharpCompress/Providers/ContextRequiredDecompressionProviderBase.cs new file mode 100644 index 00000000..fac51678 --- /dev/null +++ b/src/SharpCompress/Providers/ContextRequiredDecompressionProviderBase.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpCompress.Providers; + +public abstract class ContextRequiredDecompressionProviderBase : DecompressionOnlyProviderBase +{ + protected abstract string DecompressionContextRequirementDescription { get; } + + protected virtual string DecompressionContextRequirementSuffix => string.Empty; + + public sealed override Stream CreateDecompressStream(Stream source) => + throw new InvalidOperationException( + $"{DecompressionContextRequirementDescription}. " + + $"Use CreateDecompressStream(Stream, CompressionContext) overload{DecompressionContextRequirementSuffix}." + ); + + public sealed override ValueTask CreateDecompressStreamAsync( + Stream source, + CancellationToken cancellationToken = default + ) => + throw new InvalidOperationException( + $"{DecompressionContextRequirementDescription}. " + + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) " + + $"overload{DecompressionContextRequirementSuffix}." + ); +} diff --git a/src/SharpCompress/Providers/DecompressionOnlyProviderBase.cs b/src/SharpCompress/Providers/DecompressionOnlyProviderBase.cs new file mode 100644 index 00000000..bdd8e561 --- /dev/null +++ b/src/SharpCompress/Providers/DecompressionOnlyProviderBase.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; +using SharpCompress.Common; + +namespace SharpCompress.Providers; + +public abstract class DecompressionOnlyProviderBase : CompressionProviderBase +{ + public override bool SupportsCompression => false; + public override bool SupportsDecompression => true; + + protected abstract string CompressionNotSupportedMessage { get; } + + public sealed override Stream CreateCompressStream(Stream destination, int compressionLevel) => + throw new NotSupportedException(CompressionNotSupportedMessage); + + public sealed override Stream CreateCompressStream( + Stream destination, + int compressionLevel, + CompressionContext context + ) => throw new NotSupportedException(CompressionNotSupportedMessage); +} diff --git a/src/SharpCompress/Providers/Default/BZip2CompressionProvider.cs b/src/SharpCompress/Providers/Default/BZip2CompressionProvider.cs index 4a29ee73..aa8bf557 100644 --- a/src/SharpCompress/Providers/Default/BZip2CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/BZip2CompressionProvider.cs @@ -22,27 +22,11 @@ public sealed class BZip2CompressionProvider : CompressionProviderBase return BZip2Stream.Create(destination, CompressionMode.Compress, false); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for BZip2 compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return BZip2Stream.Create(source, CompressionMode.Decompress, false); } - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for BZip2 decompression - return CreateDecompressStream(source); - } - public override async ValueTask CreateDecompressStreamAsync( Stream source, CancellationToken cancellationToken = default @@ -52,14 +36,4 @@ public sealed class BZip2CompressionProvider : CompressionProviderBase .CreateAsync(source, CompressionMode.Decompress, false, false, cancellationToken) .ConfigureAwait(false); } - - public override async ValueTask CreateDecompressStreamAsync( - Stream source, - CompressionContext context, - CancellationToken cancellationToken = default - ) - { - // Context not used for BZip2 decompression - return await CreateDecompressStreamAsync(source, cancellationToken).ConfigureAwait(false); - } } diff --git a/src/SharpCompress/Providers/Default/Deflate64CompressionProvider.cs b/src/SharpCompress/Providers/Default/Deflate64CompressionProvider.cs index 38f22e22..482cdfe0 100644 --- a/src/SharpCompress/Providers/Default/Deflate64CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/Deflate64CompressionProvider.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using SharpCompress.Common; using SharpCompress.Compressors; @@ -10,38 +9,14 @@ namespace SharpCompress.Providers.Default; /// Provides Deflate64 decompression using SharpCompress's internal implementation. /// Note: Deflate64 compression is not supported; this provider is decompression-only. /// -public sealed class Deflate64CompressionProvider : CompressionProviderBase +public sealed class Deflate64CompressionProvider : DecompressionOnlyProviderBase { public override CompressionType CompressionType => CompressionType.Deflate64; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Deflate64 compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Deflate64 compression is not supported by SharpCompress's internal implementation." - ); - } + protected override string CompressionNotSupportedMessage => + "Deflate64 compression is not supported by SharpCompress's internal implementation."; public override Stream CreateDecompressStream(Stream source) { return new Deflate64Stream(source, CompressionMode.Decompress); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for Deflate64 decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/DeflateCompressionProvider.cs b/src/SharpCompress/Providers/Default/DeflateCompressionProvider.cs index cb5f3ba8..3a49899a 100644 --- a/src/SharpCompress/Providers/Default/DeflateCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/DeflateCompressionProvider.cs @@ -20,24 +20,8 @@ public sealed class DeflateCompressionProvider : CompressionProviderBase return new DeflateStream(destination, CompressionMode.Compress, level); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for simple Deflate compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new DeflateStream(source, CompressionMode.Decompress); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for simple Deflate decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/ExplodeCompressionProvider.cs b/src/SharpCompress/Providers/Default/ExplodeCompressionProvider.cs index 4de184ae..fb00ba89 100644 --- a/src/SharpCompress/Providers/Default/ExplodeCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/ExplodeCompressionProvider.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -15,89 +14,33 @@ namespace SharpCompress.Providers.Default; /// /// Explode requires compressed size, uncompressed size, and flags which must be provided via CompressionContext. /// -public sealed class ExplodeCompressionProvider : CompressionProviderBase +public sealed class ExplodeCompressionProvider : ContextRequiredDecompressionProviderBase { public override CompressionType CompressionType => CompressionType.Explode; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; + protected override string CompressionNotSupportedMessage => + "Explode compression is not supported by SharpCompress's internal implementation."; - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Explode compression is not supported by SharpCompress's internal implementation." - ); - } + protected override string DecompressionContextRequirementDescription => + "Explode decompression requires compressed size, uncompressed size, and flags"; - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Explode compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Explode decompression requires compressed size, uncompressed size, and flags. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload with FormatOptions." - ); - } + protected override string DecompressionContextRequirementSuffix => " with FormatOptions"; public override Stream CreateDecompressStream(Stream source, CompressionContext context) { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Explode decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - if (context.FormatOptions is not HeaderFlags flags) - { - throw new ArgumentException( - "Explode decompression requires HeaderFlags in CompressionContext.FormatOptions.", - nameof(context) - ); - } + ValidateRequiredSizes(context, "Explode"); + var flags = RequireFormatOption(context, "Explode", "HeaderFlags"); return ExplodeStream.Create(source, context.InputSize, context.OutputSize, flags); } - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Explode decompression requires compressed size, uncompressed size, and flags. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload with FormatOptions." - ); - public override async ValueTask CreateDecompressStreamAsync( Stream source, CompressionContext context, CancellationToken cancellationToken = default ) { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Explode decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - if (context.FormatOptions is not HeaderFlags flags) - { - throw new ArgumentException( - "Explode decompression requires HeaderFlags in CompressionContext.FormatOptions.", - nameof(context) - ); - } + ValidateRequiredSizes(context, "Explode"); + var flags = RequireFormatOption(context, "Explode", "HeaderFlags"); return await ExplodeStream .CreateAsync(source, context.InputSize, context.OutputSize, flags, cancellationToken) diff --git a/src/SharpCompress/Providers/Default/GZipCompressionProvider.cs b/src/SharpCompress/Providers/Default/GZipCompressionProvider.cs index a4867613..86d5704b 100644 --- a/src/SharpCompress/Providers/Default/GZipCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/GZipCompressionProvider.cs @@ -20,24 +20,8 @@ public sealed class GZipCompressionProvider : CompressionProviderBase return new GZipStream(destination, CompressionMode.Compress, level); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for simple GZip compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new GZipStream(source, CompressionMode.Decompress); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for simple GZip decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/LZipCompressionProvider.cs b/src/SharpCompress/Providers/Default/LZipCompressionProvider.cs index 607ed9b1..c4fe48b6 100644 --- a/src/SharpCompress/Providers/Default/LZipCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/LZipCompressionProvider.cs @@ -19,24 +19,8 @@ public sealed class LZipCompressionProvider : CompressionProviderBase return new LZipStream(destination, CompressionMode.Compress); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for LZip compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new LZipStream(source, CompressionMode.Decompress); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for LZip decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/LzwCompressionProvider.cs b/src/SharpCompress/Providers/Default/LzwCompressionProvider.cs index 7fe73ad4..73821cbe 100644 --- a/src/SharpCompress/Providers/Default/LzwCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/LzwCompressionProvider.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using SharpCompress.Common; using SharpCompress.Compressors.Lzw; @@ -9,38 +8,14 @@ namespace SharpCompress.Providers.Default; /// Provides LZW compression decompression using SharpCompress's internal implementation. /// Note: Compression is not supported by this provider. /// -public sealed class LzwCompressionProvider : CompressionProviderBase +public sealed class LzwCompressionProvider : DecompressionOnlyProviderBase { public override CompressionType CompressionType => CompressionType.Lzw; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "LZW compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "LZW compression is not supported by SharpCompress's internal implementation." - ); - } + protected override string CompressionNotSupportedMessage => + "LZW compression is not supported by SharpCompress's internal implementation."; public override Stream CreateDecompressStream(Stream source) { return new LzwStream(source); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for LZW decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/Reduce1CompressionProvider.cs b/src/SharpCompress/Providers/Default/Reduce1CompressionProvider.cs index fc85f319..c984b4ad 100644 --- a/src/SharpCompress/Providers/Default/Reduce1CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/Reduce1CompressionProvider.cs @@ -1,9 +1,4 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; using SharpCompress.Common; -using SharpCompress.Compressors.Reduce; namespace SharpCompress.Providers.Default; @@ -11,76 +6,8 @@ namespace SharpCompress.Providers.Default; /// Provides Reduce1 decompression using SharpCompress's internal implementation. /// Note: Reduce compression is not supported; this provider is decompression-only. /// -public sealed class Reduce1CompressionProvider : CompressionProviderBase +public sealed class Reduce1CompressionProvider : ReduceCompressionProviderBase { public override CompressionType CompressionType => CompressionType.Reduce1; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload." - ); - } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return ReduceStream.Create(source, context.InputSize, context.OutputSize, 1); - } - - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload." - ); - - public override async ValueTask CreateDecompressStreamAsync( - Stream source, - CompressionContext context, - CancellationToken cancellationToken = default - ) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return await ReduceStream - .CreateAsync(source, context.InputSize, context.OutputSize, 1, cancellationToken) - .ConfigureAwait(false); - } + protected override int Factor => 1; } diff --git a/src/SharpCompress/Providers/Default/Reduce2CompressionProvider.cs b/src/SharpCompress/Providers/Default/Reduce2CompressionProvider.cs index cd56d3b2..9ca67bf2 100644 --- a/src/SharpCompress/Providers/Default/Reduce2CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/Reduce2CompressionProvider.cs @@ -1,9 +1,4 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; using SharpCompress.Common; -using SharpCompress.Compressors.Reduce; namespace SharpCompress.Providers.Default; @@ -11,76 +6,8 @@ namespace SharpCompress.Providers.Default; /// Provides Reduce2 decompression using SharpCompress's internal implementation. /// Note: Reduce compression is not supported; this provider is decompression-only. /// -public sealed class Reduce2CompressionProvider : CompressionProviderBase +public sealed class Reduce2CompressionProvider : ReduceCompressionProviderBase { public override CompressionType CompressionType => CompressionType.Reduce2; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload." - ); - } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return ReduceStream.Create(source, context.InputSize, context.OutputSize, 2); - } - - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload." - ); - - public override async ValueTask CreateDecompressStreamAsync( - Stream source, - CompressionContext context, - CancellationToken cancellationToken = default - ) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return await ReduceStream - .CreateAsync(source, context.InputSize, context.OutputSize, 2, cancellationToken) - .ConfigureAwait(false); - } + protected override int Factor => 2; } diff --git a/src/SharpCompress/Providers/Default/Reduce3CompressionProvider.cs b/src/SharpCompress/Providers/Default/Reduce3CompressionProvider.cs index 1a28a738..01fa708c 100644 --- a/src/SharpCompress/Providers/Default/Reduce3CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/Reduce3CompressionProvider.cs @@ -1,9 +1,4 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; using SharpCompress.Common; -using SharpCompress.Compressors.Reduce; namespace SharpCompress.Providers.Default; @@ -11,76 +6,8 @@ namespace SharpCompress.Providers.Default; /// Provides Reduce3 decompression using SharpCompress's internal implementation. /// Note: Reduce compression is not supported; this provider is decompression-only. /// -public sealed class Reduce3CompressionProvider : CompressionProviderBase +public sealed class Reduce3CompressionProvider : ReduceCompressionProviderBase { public override CompressionType CompressionType => CompressionType.Reduce3; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload." - ); - } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return ReduceStream.Create(source, context.InputSize, context.OutputSize, 3); - } - - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload." - ); - - public override async ValueTask CreateDecompressStreamAsync( - Stream source, - CompressionContext context, - CancellationToken cancellationToken = default - ) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return await ReduceStream - .CreateAsync(source, context.InputSize, context.OutputSize, 3, cancellationToken) - .ConfigureAwait(false); - } + protected override int Factor => 3; } diff --git a/src/SharpCompress/Providers/Default/Reduce4CompressionProvider.cs b/src/SharpCompress/Providers/Default/Reduce4CompressionProvider.cs index efcf3e2e..14b8e543 100644 --- a/src/SharpCompress/Providers/Default/Reduce4CompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/Reduce4CompressionProvider.cs @@ -1,9 +1,4 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; using SharpCompress.Common; -using SharpCompress.Compressors.Reduce; namespace SharpCompress.Providers.Default; @@ -11,76 +6,8 @@ namespace SharpCompress.Providers.Default; /// Provides Reduce4 decompression using SharpCompress's internal implementation. /// Note: Reduce compression is not supported; this provider is decompression-only. /// -public sealed class Reduce4CompressionProvider : CompressionProviderBase +public sealed class Reduce4CompressionProvider : ReduceCompressionProviderBase { public override CompressionType CompressionType => CompressionType.Reduce4; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Reduce compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload." - ); - } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return ReduceStream.Create(source, context.InputSize, context.OutputSize, 4); - } - - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Reduce decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload." - ); - - public override async ValueTask CreateDecompressStreamAsync( - Stream source, - CompressionContext context, - CancellationToken cancellationToken = default - ) - { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Reduce decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } - - return await ReduceStream - .CreateAsync(source, context.InputSize, context.OutputSize, 4, cancellationToken) - .ConfigureAwait(false); - } + protected override int Factor => 4; } diff --git a/src/SharpCompress/Providers/Default/ReduceCompressionProviderBase.cs b/src/SharpCompress/Providers/Default/ReduceCompressionProviderBase.cs new file mode 100644 index 00000000..17b01a1a --- /dev/null +++ b/src/SharpCompress/Providers/Default/ReduceCompressionProviderBase.cs @@ -0,0 +1,36 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpCompress.Common; +using SharpCompress.Compressors.Reduce; + +namespace SharpCompress.Providers.Default; + +public abstract class ReduceCompressionProviderBase : ContextRequiredDecompressionProviderBase +{ + protected abstract int Factor { get; } + + protected override string DecompressionContextRequirementDescription => + "Reduce decompression requires compressed and uncompressed sizes"; + + protected override string CompressionNotSupportedMessage => + "Reduce compression is not supported by SharpCompress's internal implementation."; + + public sealed override Stream CreateDecompressStream(Stream source, CompressionContext context) + { + ValidateRequiredSizes(context, "Reduce"); + return ReduceStream.Create(source, context.InputSize, context.OutputSize, Factor); + } + + public sealed override async ValueTask CreateDecompressStreamAsync( + Stream source, + CompressionContext context, + CancellationToken cancellationToken = default + ) + { + ValidateRequiredSizes(context, "Reduce"); + return await ReduceStream + .CreateAsync(source, context.InputSize, context.OutputSize, Factor, cancellationToken) + .ConfigureAwait(false); + } +} diff --git a/src/SharpCompress/Providers/Default/ShrinkCompressionProvider.cs b/src/SharpCompress/Providers/Default/ShrinkCompressionProvider.cs index e539aeb4..2e26c7a7 100644 --- a/src/SharpCompress/Providers/Default/ShrinkCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/ShrinkCompressionProvider.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -15,47 +14,18 @@ namespace SharpCompress.Providers.Default; /// /// Shrink requires compressed and uncompressed sizes which must be provided via CompressionContext. /// -public sealed class ShrinkCompressionProvider : CompressionProviderBase +public sealed class ShrinkCompressionProvider : ContextRequiredDecompressionProviderBase { public override CompressionType CompressionType => CompressionType.Shrink; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; + protected override string CompressionNotSupportedMessage => + "Shrink compression is not supported by SharpCompress's internal implementation."; - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "Shrink compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "Shrink compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateDecompressStream(Stream source) - { - throw new InvalidOperationException( - "Shrink decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStream(Stream, CompressionContext) overload." - ); - } + protected override string DecompressionContextRequirementDescription => + "Shrink decompression requires compressed and uncompressed sizes"; public override Stream CreateDecompressStream(Stream source, CompressionContext context) { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Shrink decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } + ValidateRequiredSizes(context, "Shrink"); return new ShrinkStream( source, @@ -65,28 +35,13 @@ public sealed class ShrinkCompressionProvider : CompressionProviderBase ); } - public override ValueTask CreateDecompressStreamAsync( - Stream source, - CancellationToken cancellationToken = default - ) => - throw new InvalidOperationException( - "Shrink decompression requires compressed and uncompressed sizes. " - + "Use CreateDecompressStreamAsync(Stream, CompressionContext, CancellationToken) overload." - ); - public override async ValueTask CreateDecompressStreamAsync( Stream source, CompressionContext context, CancellationToken cancellationToken = default ) { - if (context.InputSize < 0 || context.OutputSize < 0) - { - throw new ArgumentException( - "Shrink decompression requires InputSize and OutputSize in CompressionContext.", - nameof(context) - ); - } + ValidateRequiredSizes(context, "Shrink"); return await ShrinkStream .CreateAsync( diff --git a/src/SharpCompress/Providers/Default/XzCompressionProvider.cs b/src/SharpCompress/Providers/Default/XzCompressionProvider.cs index 79cd97ff..db005ab0 100644 --- a/src/SharpCompress/Providers/Default/XzCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/XzCompressionProvider.cs @@ -1,4 +1,3 @@ -using System; using System.IO; using SharpCompress.Common; using SharpCompress.Compressors.Xz; @@ -9,38 +8,14 @@ namespace SharpCompress.Providers.Default; /// Provides XZ compression decompression using SharpCompress's internal implementation. /// Note: Compression is not supported by this provider. /// -public sealed class XzCompressionProvider : CompressionProviderBase +public sealed class XzCompressionProvider : DecompressionOnlyProviderBase { public override CompressionType CompressionType => CompressionType.Xz; - public override bool SupportsCompression => false; - public override bool SupportsDecompression => true; - - public override Stream CreateCompressStream(Stream destination, int compressionLevel) - { - throw new NotSupportedException( - "XZ compression is not supported by SharpCompress's internal implementation." - ); - } - - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - throw new NotSupportedException( - "XZ compression is not supported by SharpCompress's internal implementation." - ); - } + protected override string CompressionNotSupportedMessage => + "XZ compression is not supported by SharpCompress's internal implementation."; public override Stream CreateDecompressStream(Stream source) { return new XZStream(source); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for XZ decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/Default/ZStandardCompressionProvider.cs b/src/SharpCompress/Providers/Default/ZStandardCompressionProvider.cs index eb91f402..973e0be8 100644 --- a/src/SharpCompress/Providers/Default/ZStandardCompressionProvider.cs +++ b/src/SharpCompress/Providers/Default/ZStandardCompressionProvider.cs @@ -18,24 +18,8 @@ public sealed class ZStandardCompressionProvider : CompressionProviderBase return new ZStd.CompressionStream(destination, compressionLevel); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for ZStandard compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new ZStd.DecompressionStream(source); } - - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for ZStandard decompression - return CreateDecompressStream(source); - } } diff --git a/src/SharpCompress/Providers/System/SystemDeflateCompressionProvider.cs b/src/SharpCompress/Providers/System/SystemDeflateCompressionProvider.cs index 41f0d97b..8e5faa01 100644 --- a/src/SharpCompress/Providers/System/SystemDeflateCompressionProvider.cs +++ b/src/SharpCompress/Providers/System/SystemDeflateCompressionProvider.cs @@ -23,16 +23,6 @@ public sealed class SystemDeflateCompressionProvider : CompressionProviderBase return new DeflateStream(destination, bclLevel, leaveOpen: false); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for simple Deflate compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new DeflateStream( @@ -42,12 +32,6 @@ public sealed class SystemDeflateCompressionProvider : CompressionProviderBase ); } - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for simple Deflate decompression - return CreateDecompressStream(source); - } - /// /// Maps SharpCompress compression level (0-9) to BCL CompressionLevel. /// diff --git a/src/SharpCompress/Providers/System/SystemGZipCompressionProvider.cs b/src/SharpCompress/Providers/System/SystemGZipCompressionProvider.cs index 35dd5266..d0335ef6 100644 --- a/src/SharpCompress/Providers/System/SystemGZipCompressionProvider.cs +++ b/src/SharpCompress/Providers/System/SystemGZipCompressionProvider.cs @@ -23,16 +23,6 @@ public sealed class SystemGZipCompressionProvider : CompressionProviderBase return new GZipStream(destination, bclLevel, leaveOpen: false); } - public override Stream CreateCompressStream( - Stream destination, - int compressionLevel, - CompressionContext context - ) - { - // Context not used for simple GZip compression - return CreateCompressStream(destination, compressionLevel); - } - public override Stream CreateDecompressStream(Stream source) { return new GZipStream( @@ -42,12 +32,6 @@ public sealed class SystemGZipCompressionProvider : CompressionProviderBase ); } - public override Stream CreateDecompressStream(Stream source, CompressionContext context) - { - // Context not used for simple GZip decompression - return CreateDecompressStream(source); - } - /// /// Maps SharpCompress compression level (0-9) to BCL CompressionLevel. ///