diff --git a/src/libraries/Common/src/Interop/Interop.zlib.cs b/src/libraries/Common/src/Interop/Interop.zlib.cs index 0ca40a2c712211..97c4c46af42023 100644 --- a/src/libraries/Common/src/Interop/Interop.zlib.cs +++ b/src/libraries/Common/src/Interop/Interop.zlib.cs @@ -23,6 +23,9 @@ internal static unsafe partial ZLibNative.ErrorCode DeflateInit2_( [LibraryImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_DeflateEnd")] internal static unsafe partial ZLibNative.ErrorCode DeflateEnd(ZLibNative.ZStream* stream); + [LibraryImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_DeflateReset")] + internal static unsafe partial ZLibNative.ErrorCode DeflateReset(ZLibNative.ZStream* stream); + [LibraryImport(Libraries.CompressionNative, EntryPoint = "CompressionNative_InflateInit2_")] internal static unsafe partial ZLibNative.ErrorCode InflateInit2_(ZLibNative.ZStream* stream, int windowBits); diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs index 195910dc00e756..e2ef5b388eb702 100644 --- a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs @@ -333,6 +333,28 @@ public unsafe ErrorCode Deflate(FlushCode flush) } } + public unsafe ErrorCode DeflateReset() + { + bool refAdded = false; + try + { + DangerousAddRef(ref refAdded); + EnsureState(State.InitializedForDeflate); + + fixed (ZStream* stream = &_zStream) + { + return Interop.ZLib.DeflateReset(stream); + } + } + finally + { + if (refAdded) + { + DangerousRelease(); + } + } + } + private unsafe ErrorCode DeflateEnd() { EnsureState(State.InitializedForDeflate); diff --git a/src/libraries/Common/tests/System/IO/Compression/EncoderDecoderTestBase.cs b/src/libraries/Common/tests/System/IO/Compression/EncoderDecoderTestBase.cs index c7d5a248c64163..9492c2bb185b16 100644 --- a/src/libraries/Common/tests/System/IO/Compression/EncoderDecoderTestBase.cs +++ b/src/libraries/Common/tests/System/IO/Compression/EncoderDecoderTestBase.cs @@ -557,6 +557,94 @@ public void Reset_AllowsReuseForMultipleDecompressions(bool useDictionary) } } + [Fact] + public void Reset_OnFreshInstance_IsNoOp() + { + if (!SupportsReset) + return; + + byte[] input = CreateTestData(); + + using EncoderAdapter encoder = CreateEncoder(ValidQuality, ValidWindowLog); + encoder.Reset(); + encoder.Reset(); + + byte[] compressed = new byte[GetMaxCompressedLength(input.Length)]; + OperationStatus compressStatus = encoder.Compress(input, compressed, out int consumed, out int compressedLength, isFinalBlock: true); + Assert.Equal(OperationStatus.Done, compressStatus); + Assert.Equal(input.Length, consumed); + + using DecoderAdapter decoder = CreateDecoder(); + decoder.Reset(); + decoder.Reset(); + + byte[] output = new byte[input.Length]; + OperationStatus decompressStatus = decoder.Decompress(compressed.AsSpan(0, compressedLength), output, out _, out int written); + Assert.Equal(OperationStatus.Done, decompressStatus); + Assert.Equal(input.Length, written); + Assert.Equal(input, output); + } + + [Fact] + public void Reset_AfterUnfinishedCompression_ProducesIndependentStream() + { + if (!SupportsReset) + return; + + byte[] input = CreateTestData(); + + using EncoderAdapter encoder = CreateEncoder(ValidQuality, ValidWindowLog); + + // Start compressing without finalizing, leaving the encoder mid-operation. + byte[] scratch = new byte[GetMaxCompressedLength(input.Length)]; + encoder.Compress(input, scratch, out _, out _, isFinalBlock: false); + + // Reset must discard the in-progress state so the next operation is independent. + encoder.Reset(); + + byte[] compressed = new byte[GetMaxCompressedLength(input.Length)]; + OperationStatus status = encoder.Compress(input, compressed, out int consumed, out int compressedLength, isFinalBlock: true); + Assert.Equal(OperationStatus.Done, status); + Assert.Equal(input.Length, consumed); + + // The produced stream must be a valid, complete stream that round-trips. + byte[] output = new byte[input.Length]; + using DecoderAdapter decoder = CreateDecoder(); + OperationStatus decompressStatus = decoder.Decompress(compressed.AsSpan(0, compressedLength), output, out _, out int written); + Assert.Equal(OperationStatus.Done, decompressStatus); + Assert.Equal(input.Length, written); + Assert.Equal(input, output); + } + + [Fact] + public void Reset_AfterPartialDecompression_ProducesIndependentResult() + { + if (!SupportsReset) + return; + + byte[] input = CreateTestData(); + byte[] compressed = new byte[GetMaxCompressedLength(input.Length)]; + Assert.True(TryCompress(input, compressed, out int compressedLength)); + compressed = compressed.AsSpan(0, compressedLength).ToArray(); + + using DecoderAdapter decoder = CreateDecoder(); + + // Decompress into a buffer too small to hold the full result, leaving the decoder mid-stream. + byte[] tooSmall = new byte[input.Length / 2]; + OperationStatus partialStatus = decoder.Decompress(compressed, tooSmall, out _, out _); + Assert.Equal(OperationStatus.DestinationTooSmall, partialStatus); + + // Reset must discard the partial state so the same stream can be decoded from scratch. + decoder.Reset(); + + byte[] output = new byte[input.Length]; + OperationStatus status = decoder.Decompress(compressed, output, out int consumed, out int written); + Assert.Equal(OperationStatus.Done, status); + Assert.Equal(compressed.Length, consumed); + Assert.Equal(input.Length, written); + Assert.Equal(input, output); + } + [Theory] [MemberData(nameof(GetRoundTripTestData))] public void RoundTrip_SuccessfullyCompressesAndDecompresses(int quality, bool useDictionary, bool staticEncode, bool staticDecode) diff --git a/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs b/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs index 8bbb51349de5d8..536d781eacd0ba 100644 --- a/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs +++ b/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs @@ -23,6 +23,7 @@ public sealed partial class DeflateDecoder : System.IDisposable public DeflateDecoder() { } public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan source, System.Span destination, out int bytesConsumed, out int bytesWritten) { throw null; } public void Dispose() { } + public void Reset() { } public static bool TryDecompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } public sealed partial class DeflateEncoder : System.IDisposable @@ -35,6 +36,7 @@ public DeflateEncoder(System.IO.Compression.ZLibCompressionOptions options) { } public void Dispose() { } public System.Buffers.OperationStatus Flush(System.Span destination, out int bytesWritten) { throw null; } public static long GetMaxCompressedLength(long inputLength) { throw null; } + public void Reset() { } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality, int windowLog2) { throw null; } @@ -80,6 +82,7 @@ public sealed partial class GZipDecoder : System.IDisposable public GZipDecoder() { } public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan source, System.Span destination, out int bytesConsumed, out int bytesWritten) { throw null; } public void Dispose() { } + public void Reset() { } public static bool TryDecompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } public sealed partial class GZipEncoder : System.IDisposable @@ -92,6 +95,7 @@ public GZipEncoder(System.IO.Compression.ZLibCompressionOptions options) { } public void Dispose() { } public System.Buffers.OperationStatus Flush(System.Span destination, out int bytesWritten) { throw null; } public static long GetMaxCompressedLength(long inputLength) { throw null; } + public void Reset() { } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality, int windowLog2) { throw null; } @@ -227,6 +231,7 @@ public sealed partial class ZLibDecoder : System.IDisposable public ZLibDecoder() { } public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan source, System.Span destination, out int bytesConsumed, out int bytesWritten) { throw null; } public void Dispose() { } + public void Reset() { } public static bool TryDecompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } } public sealed partial class ZLibEncoder : System.IDisposable @@ -239,6 +244,7 @@ public ZLibEncoder(System.IO.Compression.ZLibCompressionOptions options) { } public void Dispose() { } public System.Buffers.OperationStatus Flush(System.Span destination, out int bytesWritten) { throw null; } public static long GetMaxCompressedLength(long inputLength) { throw null; } + public void Reset() { } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality) { throw null; } public static bool TryCompress(System.ReadOnlySpan source, System.Span destination, out int bytesWritten, int quality, int windowLog2) { throw null; } diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateDecoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateDecoder.cs index 66ce9a7d3ef80f..0af345fe6326e6 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateDecoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateDecoder.cs @@ -13,6 +13,7 @@ namespace System.IO.Compression public sealed class DeflateDecoder : IDisposable { private ZLibNative.ZLibStreamHandle? _state; + private readonly int _windowBits; private bool _disposed; private bool _finished; @@ -27,6 +28,7 @@ public DeflateDecoder() internal DeflateDecoder(int windowBits) { + _windowBits = windowBits; _state = ZLibNative.ZLibStreamHandle.CreateForInflate(windowBits); } @@ -53,6 +55,7 @@ private void EnsureNotDisposed() /// When this method returns, the total number of bytes that were read from . /// When this method returns, the total number of bytes that were written to . /// One of the enumeration values that describes the status with which the span-based operation finished. + /// The decoder has been disposed. public OperationStatus Decompress(ReadOnlySpan source, Span destination, out int bytesConsumed, out int bytesWritten) { EnsureNotDisposed(); @@ -106,6 +109,22 @@ public OperationStatus Decompress(ReadOnlySpan source, Span destinat } } + /// + /// Resets the decoder to its initial state so the same instance can be reused for a new, independent decompression operation. + /// + /// + /// After this method returns, any sliding-window history from a previous decompression is discarded. + /// + /// The decoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + Debug.Assert(_state is not null); + + _state.InflateReset2_(_windowBits); + _finished = false; + } + /// /// Tries to decompress a source byte span into a destination span. /// diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateEncoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateEncoder.cs index 4b036d2a56bad6..f90a62291459f7 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateEncoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateEncoder.cs @@ -296,6 +296,22 @@ public OperationStatus Flush(Span destination, out int bytesWritten) } } + /// + /// Resets the encoder to its initial state so the same instance can be reused for a new, independent compression operation. + /// + /// + /// The encoder keeps the compression quality and window size it was created with. Any pending output or unflushed input from a previous, unfinished compression is discarded. + /// + /// The encoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + Debug.Assert(_state is not null); + + _state.DeflateReset(); + _finished = false; + } + /// /// Tries to compress a source byte span into a destination span using the default quality. /// diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipDecoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipDecoder.cs index 6202c7cc1c8dc8..8cebd403089f64 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipDecoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipDecoder.cs @@ -50,6 +50,19 @@ public OperationStatus Decompress(ReadOnlySpan source, Span destinat return _deflateDecoder.Decompress(source, destination, out bytesConsumed, out bytesWritten); } + /// + /// Resets the decoder to its initial state so the same instance can be reused for a new, independent decompression operation. + /// + /// + /// After this method returns, any sliding-window history from a previous decompression is discarded. + /// + /// The decoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + _deflateDecoder.Reset(); + } + /// /// Tries to decompress a source byte span into a destination span. /// diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipEncoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipEncoder.cs index b839dae37a03ed..8c5442bf497f76 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipEncoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/GZipEncoder.cs @@ -119,6 +119,19 @@ public OperationStatus Flush(Span destination, out int bytesWritten) return _deflateEncoder.Flush(destination, out bytesWritten); } + /// + /// Resets the encoder to its initial state so the same instance can be reused for a new, independent compression operation. + /// + /// + /// The encoder keeps the compression quality and window size it was created with. Any pending output or unflushed input from a previous, unfinished compression is discarded. + /// + /// The encoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + _deflateEncoder.Reset(); + } + /// /// Tries to compress a source byte span into a destination span using the default quality. /// diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibDecoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibDecoder.cs index 7eaf6d4140c6fb..d22933d3db8431 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibDecoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibDecoder.cs @@ -44,12 +44,26 @@ private void EnsureNotDisposed() /// When this method returns, the total number of bytes that were read from . /// When this method returns, the total number of bytes that were written to . /// One of the enumeration values that describes the status with which the span-based operation finished. + /// The decoder has been disposed. public OperationStatus Decompress(ReadOnlySpan source, Span destination, out int bytesConsumed, out int bytesWritten) { EnsureNotDisposed(); return _deflateDecoder.Decompress(source, destination, out bytesConsumed, out bytesWritten); } + /// + /// Resets the decoder to its initial state so the same instance can be reused for a new, independent decompression operation. + /// + /// + /// After this method returns, any sliding-window history from a previous decompression is discarded. + /// + /// The decoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + _deflateDecoder.Reset(); + } + /// /// Tries to decompress a source byte span into a destination span. /// diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibEncoder.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibEncoder.cs index 42091b946ce526..0749efc0b55ffa 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibEncoder.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZLibEncoder.cs @@ -111,6 +111,19 @@ public OperationStatus Flush(Span destination, out int bytesWritten) return _deflateEncoder.Flush(destination, out bytesWritten); } + /// + /// Resets the encoder to its initial state so the same instance can be reused for a new, independent compression operation. + /// + /// + /// The encoder keeps the compression quality and window size it was created with. Any pending output or unflushed input from a previous, unfinished compression is discarded. + /// + /// The encoder has been disposed. + public void Reset() + { + EnsureNotDisposed(); + _deflateEncoder.Reset(); + } + /// /// Tries to compress a source byte span into a destination span using the default quality. /// diff --git a/src/libraries/System.IO.Compression/tests/DeflateEncoderDecoderTests.cs b/src/libraries/System.IO.Compression/tests/DeflateEncoderDecoderTests.cs index 246fa6cc7f55cb..52fbad18252159 100644 --- a/src/libraries/System.IO.Compression/tests/DeflateEncoderDecoderTests.cs +++ b/src/libraries/System.IO.Compression/tests/DeflateEncoderDecoderTests.cs @@ -24,7 +24,7 @@ public override OperationStatus Flush(Span destination, out int bytesWritt _encoder.Flush(destination, out bytesWritten); public override void Dispose() => _encoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _encoder.Reset(); } public class DeflateDecoderAdapter : DecoderAdapter @@ -40,7 +40,7 @@ public override OperationStatus Decompress(ReadOnlySpan source, Span _decoder.Decompress(source, destination, out bytesConsumed, out bytesWritten); public override void Dispose() => _decoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _decoder.Reset(); } protected override EncoderAdapter CreateEncoder() => diff --git a/src/libraries/System.IO.Compression/tests/GZipEncoderDecoderTests.cs b/src/libraries/System.IO.Compression/tests/GZipEncoderDecoderTests.cs index 9f0e6340a3aab5..ca6ed4ddccc291 100644 --- a/src/libraries/System.IO.Compression/tests/GZipEncoderDecoderTests.cs +++ b/src/libraries/System.IO.Compression/tests/GZipEncoderDecoderTests.cs @@ -24,7 +24,7 @@ public override OperationStatus Flush(Span destination, out int bytesWritt _encoder.Flush(destination, out bytesWritten); public override void Dispose() => _encoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _encoder.Reset(); } public class GZipDecoderAdapter : DecoderAdapter @@ -40,7 +40,7 @@ public override OperationStatus Decompress(ReadOnlySpan source, Span _decoder.Decompress(source, destination, out bytesConsumed, out bytesWritten); public override void Dispose() => _decoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _decoder.Reset(); } protected override EncoderAdapter CreateEncoder() => diff --git a/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTestBase.cs b/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTestBase.cs index 13174f9b87430e..4c7cb2b477915d 100644 --- a/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTestBase.cs +++ b/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTestBase.cs @@ -9,7 +9,7 @@ namespace System.IO.Compression public abstract class ZLibEncoderDecoderTestBase : EncoderDecoderTestBase { protected override bool SupportsDictionaries => false; - protected override bool SupportsReset => false; + protected override bool SupportsReset => true; protected override string WindowLogParamName => "windowLog2"; protected override string InputLengthParamName => "inputLength"; diff --git a/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTests.cs b/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTests.cs index e4e09f0ebf60fb..c6d649086a2df3 100644 --- a/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTests.cs +++ b/src/libraries/System.IO.Compression/tests/ZLibEncoderDecoderTests.cs @@ -24,7 +24,7 @@ public override OperationStatus Flush(Span destination, out int bytesWritt _encoder.Flush(destination, out bytesWritten); public override void Dispose() => _encoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _encoder.Reset(); } public class ZLibDecoderAdapter : DecoderAdapter @@ -40,7 +40,7 @@ public override OperationStatus Decompress(ReadOnlySpan source, Span _decoder.Decompress(source, destination, out bytesConsumed, out bytesWritten); public override void Dispose() => _decoder.Dispose(); - public override void Reset() => throw new NotSupportedException(); + public override void Reset() => _decoder.Reset(); } protected override EncoderAdapter CreateEncoder() => diff --git a/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native.def b/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native.def index 736cbbcab8aebd..34496cc73b6bad 100644 --- a/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native.def +++ b/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native.def @@ -17,6 +17,7 @@ EXPORTS CompressionNative_Deflate CompressionNative_DeflateEnd CompressionNative_DeflateInit2_ + CompressionNative_DeflateReset CompressionNative_Inflate CompressionNative_InflateEnd CompressionNative_InflateInit2_ diff --git a/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native_unixexports.src b/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native_unixexports.src index 4b6725b1c0820d..fbb9536b99cc82 100644 --- a/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native_unixexports.src +++ b/src/native/libs/System.IO.Compression.Native/System.IO.Compression.Native_unixexports.src @@ -17,6 +17,7 @@ CompressionNative_Crc32 CompressionNative_Deflate CompressionNative_DeflateEnd CompressionNative_DeflateInit2_ +CompressionNative_DeflateReset CompressionNative_Inflate CompressionNative_InflateEnd CompressionNative_InflateInit2_ diff --git a/src/native/libs/System.IO.Compression.Native/entrypoints.c b/src/native/libs/System.IO.Compression.Native/entrypoints.c index 84767e534df162..4b72f5d3c0fb35 100644 --- a/src/native/libs/System.IO.Compression.Native/entrypoints.c +++ b/src/native/libs/System.IO.Compression.Native/entrypoints.c @@ -37,6 +37,7 @@ static const Entry s_compressionNative[] = DllImportEntry(CompressionNative_Deflate) DllImportEntry(CompressionNative_DeflateEnd) DllImportEntry(CompressionNative_DeflateInit2_) + DllImportEntry(CompressionNative_DeflateReset) DllImportEntry(CompressionNative_Inflate) DllImportEntry(CompressionNative_InflateEnd) DllImportEntry(CompressionNative_InflateInit2_) diff --git a/src/native/libs/System.IO.Compression.Native/pal_zlib.c b/src/native/libs/System.IO.Compression.Native/pal_zlib.c index da8f6ee83e7b0c..8ea72ec351ea34 100644 --- a/src/native/libs/System.IO.Compression.Native/pal_zlib.c +++ b/src/native/libs/System.IO.Compression.Native/pal_zlib.c @@ -152,6 +152,17 @@ int32_t CompressionNative_DeflateEnd(PAL_ZStream* stream) return result; } +int32_t CompressionNative_DeflateReset(PAL_ZStream* stream) +{ + assert(stream != NULL); + + z_stream* zStream = GetCurrentZStream(stream); + int32_t result = deflateReset(zStream); + TransferStateToPalZStream(zStream, stream); + + return result; +} + int32_t CompressionNative_InflateInit2_(PAL_ZStream* stream, int32_t windowBits) { assert(stream != NULL); diff --git a/src/native/libs/System.IO.Compression.Native/pal_zlib.h b/src/native/libs/System.IO.Compression.Native/pal_zlib.h index 56dfdaba17de45..9e67bbc8da1c99 100644 --- a/src/native/libs/System.IO.Compression.Native/pal_zlib.h +++ b/src/native/libs/System.IO.Compression.Native/pal_zlib.h @@ -102,6 +102,16 @@ Returns a PAL_ErrorCode indicating success or an error number on failure. */ FUNCTIONEXPORT int32_t FUNCTIONCALLINGCONVENTION CompressionNative_DeflateEnd(PAL_ZStream* stream); +/* +This function is equivalent to CompressionNative_DeflateEnd followed by CompressionNative_DeflateInit2_, +but does not free and reallocate the internal compression state. The stream preserves the original +initialization settings (compression level, window bits, memory level, and strategy) that were supplied +to CompressionNative_DeflateInit2_. + +Returns a PAL_ErrorCode indicating success or an error number on failure. +*/ +FUNCTIONEXPORT int32_t FUNCTIONCALLINGCONVENTION CompressionNative_DeflateReset(PAL_ZStream* stream); + /* Initializes the PAL_ZStream so the Inflate function can be invoked on it.