Skip to content

Commit 0e83dfa

Browse files
committed
Add ctor overloads
1 parent b4a55d1 commit 0e83dfa

File tree

5 files changed

+125
-2
lines changed

5 files changed

+125
-2
lines changed

src/libraries/System.IO.Compression.ZStandard/ref/System.IO.Compression.ZStandard.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public ZstandardStream(System.IO.Stream stream, System.IO.Compression.Compressio
6060
public ZstandardStream(System.IO.Stream stream, System.IO.Compression.CompressionMode mode) { }
6161
public ZstandardStream(System.IO.Stream stream, System.IO.Compression.CompressionMode mode, bool leaveOpen) { }
6262
public ZstandardStream(System.IO.Stream stream, System.IO.Compression.ZstandardCompressionOptions compressionOptions, bool leaveOpen = false) { }
63+
public ZstandardStream(System.IO.Stream stream, System.IO.Compression.ZstandardDecoder decoder, bool leaveOpen = false) { }
64+
public ZstandardStream(System.IO.Stream stream, System.IO.Compression.ZstandardEncoder encoder, bool leaveOpen = false) { }
6365
public System.IO.Stream BaseStream { get { throw null; } }
6466
public override bool CanRead { get { throw null; } }
6567
public override bool CanSeek { get { throw null; } }

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZStandardStream.Compress.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ public ZstandardStream(Stream stream, ZstandardCompressionOptions compressionOpt
4444
}
4545
}
4646

47+
/// <summary>Initializes a new instance of the <see cref="ZstandardStream" /> class by using the specified stream and encoder instance.</summary>
48+
/// <param name="stream">The stream to which compressed data is written.</param>
49+
/// <param name="encoder">The encoder instance to use for compression. The stream will not dispose this encoder; instead, it will reset it when the stream is disposed.</param>
50+
/// <param name="leaveOpen"><see langword="true" /> to leave the stream open after the <see cref="ZstandardStream" /> object is disposed; otherwise, <see langword="false" />.</param>
51+
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is <see langword="null"/>.</exception>
52+
/// <exception cref="ArgumentException"><paramref name="stream"/> does not support writing.</exception>
53+
public ZstandardStream(Stream stream, ZstandardEncoder encoder, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
54+
{
55+
_encoder = encoder;
56+
_encoderOwned = false;
57+
}
58+
4759
private void WriteCore(ReadOnlySpan<byte> buffer, bool isFinalBlock = false, bool flush = false, bool checkActiveRWOps = true)
4860
{
4961
if (_mode != CompressionMode.Compress)

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZStandardStream.Decompress.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ public sealed partial class ZstandardStream
1515
private int _bufferCount;
1616
private bool _nonEmptyInput;
1717

18+
/// <summary>Initializes a new instance of the <see cref="ZstandardStream" /> class by using the specified stream and decoder instance.</summary>
19+
/// <param name="stream">The stream from which data to decompress is read.</param>
20+
/// <param name="decoder">The decoder instance to use for decompression. The stream will not dispose this decoder; instead, it will reset it when the stream is disposed.</param>
21+
/// <param name="leaveOpen"><see langword="true" /> to leave the stream open after the <see cref="ZstandardStream" /> object is disposed; otherwise, <see langword="false" />.</param>
22+
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is <see langword="null"/>.</exception>
23+
/// <exception cref="ArgumentException"><paramref name="stream"/> does not support reading.</exception>
24+
public ZstandardStream(Stream stream, ZstandardDecoder decoder, bool leaveOpen = false) : this(stream, CompressionMode.Decompress, leaveOpen)
25+
{
26+
_decoder = decoder;
27+
_decoderOwned = false;
28+
}
29+
1830
private bool TryDecompress(Span<byte> destination, out int bytesWritten)
1931
{
2032
// Decompress any data we may have in our buffer.

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZstandardStream.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public sealed partial class ZstandardStream : Stream
1818
private readonly CompressionMode _mode;
1919
private volatile bool _activeRwOperation;
2020

21+
// These fields track whether the encoder/decoder are owned by this stream instance
22+
// When owned, they are disposed; when not owned, they are reset
23+
private bool _encoderOwned = true;
24+
private bool _decoderOwned = true;
25+
2126
/// <summary>Initializes a new instance of the <see cref="ZstandardStream" /> class by using the specified stream and compression mode.</summary>
2227
/// <param name="stream">The stream to which compressed data is written or from which data to decompress is read.</param>
2328
/// <param name="mode">One of the enumeration values that indicates whether to compress data to the stream or decompress data from the stream.</param>
@@ -163,8 +168,24 @@ public override async ValueTask DisposeAsync()
163168
private void ReleaseStateForDispose()
164169
{
165170
_stream = null!;
166-
_encoder.Dispose();
167-
_decoder.Dispose();
171+
172+
if (_encoderOwned)
173+
{
174+
_encoder.Dispose();
175+
}
176+
else
177+
{
178+
_encoder.Reset();
179+
}
180+
181+
if (_decoderOwned)
182+
{
183+
_decoder.Dispose();
184+
}
185+
else
186+
{
187+
_decoder.Reset();
188+
}
168189

169190
byte[] buffer = _buffer;
170191
if (buffer != null)

src/libraries/System.IO.Compression.ZStandard/tests/CompressionStreamUnitTests.ZStandard.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Buffers;
45
using System.Threading.Tasks;
56
using Xunit;
67

@@ -24,5 +25,80 @@ public override Stream CreateStream(Stream stream, ZLibCompressionOptions option
2425
public override int BufferSize => 1 << 16;
2526

2627
protected override string CompressedTestFile(string uncompressedPath) => Path.Combine("ZstandardTestData", Path.GetFileName(uncompressedPath) + ".zst");
28+
29+
[Fact]
30+
public void ZstandardStream_WithEncoder_CompressesData()
31+
{
32+
var encoder = new ZstandardEncoder(5, 10);
33+
byte[] testData = CreateTestData();
34+
using var input = new MemoryStream(testData);
35+
using var output = new MemoryStream();
36+
37+
using (var compressionStream = new ZstandardStream(output, encoder, leaveOpen: true))
38+
{
39+
input.CopyTo(compressionStream);
40+
}
41+
42+
// Verify data was compressed
43+
Assert.True(output.Length > 0);
44+
Assert.True(output.Length < testData.Length);
45+
46+
// Verify the encoder was reset, not disposed (should be reusable)
47+
using var output2 = new MemoryStream();
48+
using (var compressionStream2 = new ZstandardStream(output2, encoder, leaveOpen: true))
49+
{
50+
input.Position = 0;
51+
input.CopyTo(compressionStream2);
52+
}
53+
54+
Assert.True(output2.Length > 0);
55+
encoder.Dispose(); // Clean up
56+
}
57+
58+
[Fact]
59+
public void ZstandardStream_WithDecoder_DecompressesData()
60+
{
61+
// First, create some compressed data
62+
byte[] testData = CreateTestData();
63+
byte[] compressedData = new byte[ZstandardEncoder.GetMaxCompressedLength(testData.Length)];
64+
bool compressResult = ZstandardEncoder.TryCompress(testData, compressedData, out int compressedLength);
65+
Assert.True(compressResult);
66+
67+
Array.Resize(ref compressedData, compressedLength);
68+
69+
var decoder = new ZstandardDecoder();
70+
using var input = new MemoryStream(compressedData);
71+
using var output = new MemoryStream();
72+
73+
using (var decompressionStream = new ZstandardStream(input, decoder, leaveOpen: true))
74+
{
75+
decompressionStream.CopyTo(output);
76+
}
77+
78+
// Verify data was decompressed correctly
79+
Assert.Equal(testData, output.ToArray());
80+
81+
// Verify the decoder was reset, not disposed (should be reusable)
82+
using var output2 = new MemoryStream();
83+
using (var decompressionStream2 = new ZstandardStream(input, decoder, leaveOpen: true))
84+
{
85+
input.Position = 0;
86+
decompressionStream2.CopyTo(output2);
87+
}
88+
89+
Assert.Equal(testData, output2.ToArray());
90+
decoder.Dispose(); // Clean up
91+
}
92+
93+
private static byte[] CreateTestData()
94+
{
95+
// Create some test data that compresses well
96+
byte[] data = new byte[1000];
97+
for (int i = 0; i < data.Length; i++)
98+
{
99+
data[i] = (byte)(i % 10); // Repeating pattern
100+
}
101+
return data;
102+
}
27103
}
28104
}

0 commit comments

Comments
 (0)