Skip to content

Commit d0bc904

Browse files
authored
Add WindowLog property to BrotliCompressionOptions (#121786)
This PR adds a `WindowLog` property to `BrotliCompressionOptions` to allow developers to configure the Brotli compression window size (valid range: 10-24, default: 22). The window log controls the maximum distance for back-references in the LZ77 algorithm, where larger windows can improve compression for data with long-distance repetitions. Includes corresponding validation tests following the existing pattern established for the `Quality` property. Fixes #116227
1 parent 2a92fc1 commit d0bc904

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public sealed partial class BrotliCompressionOptions
1010
{
1111
public BrotliCompressionOptions() { }
1212
public int Quality { get { throw null; } set { } }
13+
public int WindowLog { get { throw null; } set { } }
1314
}
1415
public partial struct BrotliDecoder : System.IDisposable
1516
{

src/libraries/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliCompressionOptions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace System.IO.Compression
99
public sealed class BrotliCompressionOptions
1010
{
1111
private int _quality = BrotliUtils.Quality_Default;
12+
private int _windowLog = BrotliUtils.WindowBits_Default;
1213

1314
/// <summary>
1415
/// Gets or sets the compression quality for a Brotli compression stream.
@@ -28,5 +29,24 @@ public int Quality
2829
_quality = value;
2930
}
3031
}
32+
33+
/// <summary>
34+
/// Gets or sets the window size for a Brotli compression stream.
35+
/// </summary>
36+
/// <exception cref="ArgumentOutOfRangeException" accessor="set">The value is less than 10 or greater than 24.</exception>
37+
/// <remarks>
38+
/// The value is expressed as the base-2 logarithm of the size in bytes of the sliding window used by the LZ77 algorithm. Larger window sizes can improve compression ratio but use more memory. Range is from 10 to 24. The default value is 22.
39+
/// </remarks>
40+
public int WindowLog
41+
{
42+
get => _windowLog;
43+
set
44+
{
45+
ArgumentOutOfRangeException.ThrowIfLessThan(value, BrotliUtils.WindowBits_Min, nameof(value));
46+
ArgumentOutOfRangeException.ThrowIfGreaterThan(value, BrotliUtils.WindowBits_Max, nameof(value));
47+
48+
_windowLog = value;
49+
}
50+
}
3151
}
3252
}

src/libraries/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public BrotliStream(Stream stream, BrotliCompressionOptions compressionOptions,
4141
ArgumentNullException.ThrowIfNull(compressionOptions);
4242

4343
_encoder.SetQuality(compressionOptions.Quality);
44+
_encoder.SetWindow(compressionOptions.WindowLog);
4445
}
4546

4647
/// <summary>Writes compressed bytes to the underlying stream from the specified byte array.</summary>

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,52 @@ public void InvalidBrotliCompressionQuality()
107107
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.Quality = 12);
108108
}
109109

110+
[Fact]
111+
public void InvalidBrotliCompressionWindowLog()
112+
{
113+
BrotliCompressionOptions options = new();
114+
115+
Assert.Equal(22, options.WindowLog); // default value
116+
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.WindowLog = -1);
117+
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.WindowLog = 9);
118+
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.WindowLog = 25);
119+
}
120+
121+
[Theory]
122+
[InlineData(10)]
123+
[InlineData(15)]
124+
[InlineData(22)]
125+
[InlineData(24)]
126+
public void BrotliCompressionWindowLog_RoundTrip(int windowLog)
127+
{
128+
byte[] testData = new byte[10000];
129+
Random.Shared.NextBytes(testData);
130+
131+
// Compress with specific window size
132+
byte[] compressed;
133+
using (var ms = new MemoryStream())
134+
{
135+
using (var compressor = new BrotliStream(ms, new BrotliCompressionOptions() { WindowLog = windowLog }, leaveOpen: true))
136+
{
137+
compressor.Write(testData);
138+
}
139+
compressed = ms.ToArray();
140+
}
141+
142+
// Decompress and verify
143+
byte[] decompressed;
144+
using (var ms = new MemoryStream(compressed))
145+
using (var decompressor = new BrotliStream(ms, CompressionMode.Decompress))
146+
using (var resultStream = new MemoryStream())
147+
{
148+
decompressor.CopyTo(resultStream);
149+
decompressed = resultStream.ToArray();
150+
}
151+
152+
Assert.Equal(testData.Length, decompressed.Length);
153+
Assert.Equal<byte>(testData, decompressed);
154+
}
155+
110156
[Theory]
111157
[MemberData(nameof(UncompressedTestFilesBrotli))]
112158
public async Task BrotliCompressionQuality_SizeInOrder(string testFile)

0 commit comments

Comments
 (0)