diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.CompressionLevel.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.CompressionLevel.cs new file mode 100644 index 0000000000000..4d55f6373ef6f --- /dev/null +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.CompressionLevel.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.IO.Compression; + +internal static partial class ZLibNative +{ + /// + ///

ZLib can accept any integer value between 0 and 9 (inclusive) as a valid compression level parameter: + /// 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). + /// CompressionLevel.DefaultCompression = -1 requests a default compromise between speed and compression + /// (currently equivalent to level 6).

+ /// + ///

How to choose a compression level:

+ /// + ///

The names NoCompression, BestSpeed, DefaultCompression, BestCompression are taken over from + /// the corresponding ZLib definitions, which map to our public NoCompression, Fastest, Optimal, and SmallestSize respectively.

+ ///

Optimal Compression:

+ ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.DefaultCompression;
+ /// int windowBits = 15; // or -15 if no headers required
+ /// int memLevel = 8;
+ /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

+ /// + ///

Fastest compression:

+ ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.BestSpeed;
+ /// int windowBits = 15; // or -15 if no headers required
+ /// int memLevel = 8;
+ /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

+ /// + ///

No compression (even faster, useful for data that cannot be compressed such some image formats):

+ ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.NoCompression;
+ /// int windowBits = 15; // or -15 if no headers required
+ /// int memLevel = 7;
+ /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

+ /// + ///

Smallest Size Compression:

+ ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.BestCompression;
+ /// int windowBits = 15; // or -15 if no headers required
+ /// int memLevel = 8;
+ /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

+ ///
+ public enum CompressionLevel : int + { + NoCompression = 0, + BestSpeed = 1, + DefaultCompression = -1, + BestCompression = 9 + } +} diff --git a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs index 0113334b964e1..f5c7cf8077380 100644 --- a/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs +++ b/src/libraries/Common/src/System/IO/Compression/ZLibNative.cs @@ -37,48 +37,6 @@ public enum ErrorCode : int VersionError = -6 } - /// - ///

ZLib can accept any integer value between 0 and 9 (inclusive) as a valid compression level parameter: - /// 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). - /// CompressionLevel.DefaultCompression = -1 requests a default compromise between speed and compression - /// (currently equivalent to level 6).

- /// - ///

How to choose a compression level:

- /// - ///

The names NoCompression, BestSpeed, DefaultCompression, BestCompression are taken over from - /// the corresponding ZLib definitions, which map to our public NoCompression, Fastest, Optimal, and SmallestSize respectively.

- ///

Optimal Compression:

- ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.DefaultCompression;
- /// int windowBits = 15; // or -15 if no headers required
- /// int memLevel = 8;
- /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

- /// - ///

Fastest compression:

- ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.BestSpeed;
- /// int windowBits = 15; // or -15 if no headers required
- /// int memLevel = 8;
- /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

- /// - ///

No compression (even faster, useful for data that cannot be compressed such some image formats):

- ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.NoCompression;
- /// int windowBits = 15; // or -15 if no headers required
- /// int memLevel = 7;
- /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

- /// - ///

Smallest Size Compression:

- ///

ZLibNative.CompressionLevel compressionLevel = ZLibNative.CompressionLevel.BestCompression;
- /// int windowBits = 15; // or -15 if no headers required
- /// int memLevel = 8;
- /// ZLibNative.CompressionStrategy strategy = ZLibNative.CompressionStrategy.DefaultStrategy;

- ///
- public enum CompressionLevel : int - { - NoCompression = 0, - BestSpeed = 1, - DefaultCompression = -1, - BestCompression = 9 - } - /// ///

From the ZLib manual:

///

CompressionStrategy is used to tune the compression algorithm.
diff --git a/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs b/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs index ed6f78c56d2cd..a6635777f8583 100644 --- a/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs +++ b/src/libraries/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs @@ -497,6 +497,30 @@ async Task GetLengthAsync(CompressionLevel compressionLevel) Assert.True(optimalLength >= smallestLength); } + [Theory] + [MemberData(nameof(UncompressedTestFilesZLib))] + public async Task ZLibCompressionOptions_SizeInOrder(string testFile) + { + using var uncompressedStream = await LocalMemoryStream.readAppFileAsync(testFile); + + async Task GetLengthAsync(int compressionLevel) + { + uncompressedStream.Position = 0; + using var mms = new MemoryStream(); + using var compressor = CreateStream(mms, new ZLibCompressionOptions() { CompressionLevel = compressionLevel, CompressionStrategy = ZLibCompressionStrategy.Default }, leaveOpen: false); + await uncompressedStream.CopyToAsync(compressor); + await compressor.FlushAsync(); + return mms.Length; + } + + long fastestLength = await GetLengthAsync(1); + long optimalLength = await GetLengthAsync(5); + long smallestLength = await GetLengthAsync(9); + + Assert.True(fastestLength >= optimalLength); + Assert.True(optimalLength >= smallestLength); + } + [Theory] [MemberData(nameof(ZLibOptionsRoundTripTestData))] public async Task RoundTripWithZLibCompressionOptions(string testFile, ZLibCompressionOptions options) @@ -537,28 +561,6 @@ private async Task CompressTestFile(LocalMemoryStream testStream, return compressorOutput; } - protected async Task CompressionLevel_SizeInOrderBase(string testFile) - { - using var uncompressedStream = await LocalMemoryStream.readAppFileAsync(testFile); - - async Task GetLengthAsync(int compressionLevel) - { - uncompressedStream.Position = 0; - using var mms = new MemoryStream(); - using var compressor = CreateStream(mms, new ZLibCompressionOptions() { CompressionLevel = compressionLevel, CompressionStrategy = ZLibCompressionStrategy.Default }, leaveOpen: false); - await uncompressedStream.CopyToAsync(compressor); - await compressor.FlushAsync(); - return mms.Length; - } - - long prev = await GetLengthAsync(0); - for (int i = 1; i < 10; i++) - { - long cur = await GetLengthAsync(i); - Assert.True(cur <= prev, $"Expected {cur} <= {prev} for quality {i}"); - prev = cur; - } - } } public enum TestScenario diff --git a/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj b/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj index 167caaaa6bc84..936e3768a0e4e 100644 --- a/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj +++ b/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj @@ -27,6 +27,8 @@ + diff --git a/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj b/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj index 208844b5d67aa..9292ec1f46d83 100644 --- a/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj +++ b/src/libraries/System.IO.Compression/src/System.IO.Compression.csproj @@ -35,6 +35,8 @@ + diff --git a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs index 9c25d5e5483fb..d91a243b907cc 100644 --- a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs +++ b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs @@ -219,12 +219,5 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati return base.WriteAsync(buffer, offset, count, cancellationToken); } } - - [Theory] - [MemberData(nameof(UncompressedTestFilesZLib))] - public async Task ZLibCompressionLevel_SizeInOrder(string testFile) - { - await CompressionLevel_SizeInOrderBase(testFile); - } } } diff --git a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs index 9fabd3dc31a26..9919b2c819ae3 100644 --- a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs +++ b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs @@ -441,12 +441,5 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati return base.WriteAsync(buffer, offset, count, cancellationToken); } } - - [Theory] - [MemberData(nameof(UncompressedTestFilesZLib))] - public async Task ZLibCompressionLevel_SizeInOrder(string testFile) - { - await CompressionLevel_SizeInOrderBase(testFile); - } } } diff --git a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.ZLib.cs b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.ZLib.cs index ea868cdcf1f44..bed459833e182 100644 --- a/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.ZLib.cs +++ b/src/libraries/System.IO.Compression/tests/CompressionStreamUnitTests.ZLib.cs @@ -150,12 +150,5 @@ public void StreamTruncation_IsDetected(TestScenario testScenario) } }, testScenario.ToString()).Dispose(); } - - [Theory] - [MemberData(nameof(UncompressedTestFilesZLib))] - public async Task ZLibCompressionLevel_SizeInOrder(string testFile) - { - await CompressionLevel_SizeInOrderBase(testFile); - } } } diff --git a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj index be6e981939a7f..286ffea285025 100644 --- a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj +++ b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj @@ -35,6 +35,8 @@ + diff --git a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj index 177e95dacee0a..b60a0bf8cc463 100644 --- a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj +++ b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj @@ -37,6 +37,8 @@ Link="Common\System\Net\WebSockets\WebSocketValidate.cs" /> +