Background and motivation
This API addresses the reusability limitation reported in #129090.
.NET 11 introduced the streamless, non-allocating types DeflateEncoder / DeflateDecoder , ZLibEncoder / ZLibDecoder , and GZipEncoder / GZipDecoder. Each holds a native zlib stream and exposes instance Compress(...) / Decompress(...) methods plus static TryCompress(...) / TryDecompress(...) helpers.
The instance Compress(...) methods allow streaming the data in parts, once the compressed frame is processed, the method returns OperationStatus.Done and will not consume more data even on subsequent calls.
The problem is, that in the wild, the compressed data streams can be multiple frames back-to-back (See #25105 and dotnet/corefx#30442). With the decompressed content being the concatenation of the individual decompressed frames. The compression streams (DeflateStream, ZstandardStream, ...) detect this and will internally reset the state and transparently consume the following frames. The Decoder classes can't do the same for ambiguity reasons (in short, we are unable to distinguish between partial header and trailing garbage data, so we can't report the correct OperationStatus in all cases, see #129047 for discussion about it for Zstandard).
Right now, in order to consume multi-frame content, users need to Dispose() and new () a fresh Decoder to process the next frame. A Reset() function would avoid unnecessary reallocation of memory. Similarly, we wan't to add Reset() to Encoder classes as well to allow user-friendlier way of producing multi-frame content or reuse the Encoder to decompress multiple payloads.
API Proposal
namespace System.IO.Compression
{
public sealed partial class DeflateDecoder : System.IDisposable
{
public void Reset();
}
public sealed partial class ZLibDecoder : System.IDisposable
{
public void Reset();
}
public sealed partial class GZipDecoder : System.IDisposable
{
public void Reset();
}
public sealed partial class DeflateEncoder : System.IDisposable
{
public void Reset();
}
public sealed partial class ZLibEncoder : System.IDisposable
{
public void Reset();
}
public sealed partial class GZipEncoder : System.IDisposable
{
public void Reset();
}
}
API Usage
// Same instance decodes each independent payload.
using var decoder = new ZLibDecoder();
foreach (ReadOnlyMemory<byte> payload in payloads)
{
OperationStatus status = decoder.Decompress(payload.Span, destination, out _, out int written);
if (status == OperationStatus.Done)
{
Use(destination.AsSpan(0, written));
decoder.Reset(); // finished — ready for the next payload
}
}
Alternative Designs
No response
Risks
Low, we already have Reset() methods on ZstandardEncoder/ZstandardDecoder so we are just following established pattern.
Background and motivation
This API addresses the reusability limitation reported in #129090.
.NET 11 introduced the streamless, non-allocating types
DeflateEncoder/DeflateDecoder,ZLibEncoder/ZLibDecoder, andGZipEncoder/GZipDecoder. Each holds a native zlib stream and exposes instanceCompress(...)/Decompress(...)methods plus staticTryCompress(...)/TryDecompress(...)helpers.The instance
Compress(...)methods allow streaming the data in parts, once the compressed frame is processed, the method returnsOperationStatus.Doneand will not consume more data even on subsequent calls.The problem is, that in the wild, the compressed data streams can be multiple frames back-to-back (See #25105 and dotnet/corefx#30442). With the decompressed content being the concatenation of the individual decompressed frames. The compression streams (
DeflateStream,ZstandardStream, ...) detect this and will internally reset the state and transparently consume the following frames. The Decoder classes can't do the same for ambiguity reasons (in short, we are unable to distinguish between partial header and trailing garbage data, so we can't report the correctOperationStatusin all cases, see #129047 for discussion about it for Zstandard).Right now, in order to consume multi-frame content, users need to
Dispose()andnew ()a fresh Decoder to process the next frame. AReset()function would avoid unnecessary reallocation of memory. Similarly, we wan't to addReset()to Encoder classes as well to allow user-friendlier way of producing multi-frame content or reuse the Encoder to decompress multiple payloads.API Proposal
API Usage
Alternative Designs
No response
Risks
Low, we already have
Reset()methods onZstandardEncoder/ZstandardDecoderso we are just following established pattern.