Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call native BrotliEncoderMaxCompressedSize method for BrotliEncoder.GetMaxCompressedLength #108043

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/libraries/Common/src/Interop/Interop.Brotli.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ internal static unsafe partial BOOL BrotliEncoderCompressStream(
[LibraryImport(Libraries.CompressionNative)]
internal static partial BOOL BrotliEncoderHasMoreOutput(SafeBrotliEncoderHandle state);

[LibraryImport(Libraries.CompressionNative)]
internal static partial nuint BrotliEncoderMaxCompressedSize(nuint inputSize);

[LibraryImport(Libraries.CompressionNative)]
internal static partial void BrotliEncoderDestroyInstance(IntPtr state);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal static partial class BrotliUtils
public const int Quality_Min = 0;
public const int Quality_Default = 4;
public const int Quality_Max = 11;
public const int MaxInputSize = int.MaxValue - 515; // 515 is the max compressed extra bytes
public const int MaxInputSize = int.MaxValue - 524_166; // 524_166 is the max compressed extra bytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this number come from?

Copy link
Member Author

@buyaa-n buyaa-n Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before int.MaxValue - 515 = 2_147_483_132 was producing max compressed length, i.e. GetMaxCompressedLength(2_147_483_132)) returned int.MaxValue. Now this produces negative number

After testing with various values now this value equals 524_166 and GetMaxCompressedLength(int.MaxValue - 524_166))producesint.MaxValue`

The comment is not that clear, but do not have a better version


internal static int GetQualityFromCompressionLevel(CompressionLevel compressionLevel) =>
compressionLevel switch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,26 +103,16 @@ internal void SetWindow(int window)
}

/// <summary>Gets the maximum expected compressed length for the provided input size.</summary>
/// <param name="inputSize">The input size to get the maximum expected compressed length from. Must be greater or equal than 0 and less or equal than <see cref="int.MaxValue" /> - 515.</param>
/// <param name="inputSize">The input size to get the maximum expected compressed length from. Must be greater or equal than 0 and less or equal than <see cref="int.MaxValue" /> - 524166.</param>
/// <returns>A number representing the maximum compressed length for the provided input size.</returns>
/// <remarks>Returns 1 if <paramref name="inputSize" /> is 0.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="inputSize" /> is less than 0, the minimum allowed input size, or greater than <see cref="int.MaxValue" /> - 515, the maximum allowed input size.</exception>
/// <remarks>Returns 2 if <paramref name="inputSize" /> is 0.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="inputSize" /> is less than 0, the minimum allowed input size, or greater than <see cref="int.MaxValue" /> - 524166, the maximum allowed input size.</exception>
public static int GetMaxCompressedLength(int inputSize)
{
ArgumentOutOfRangeException.ThrowIfNegative(inputSize);
ArgumentOutOfRangeException.ThrowIfGreaterThan(inputSize, BrotliUtils.MaxInputSize);

if (inputSize == 0)
{
return 1;
}

int numLargeBlocks = inputSize >> 24;
int tail = inputSize & 0xFFFFFF;
int tailOverhead = (tail > (1 << 20)) ? 4 : 3;
int overhead = 2 + (4 * numLargeBlocks) + tailOverhead + 1;
int result = inputSize + overhead;
return result;
return (int)Interop.Brotli.BrotliEncoderMaxCompressedSize((nuint)inputSize);
}

internal OperationStatus Flush(Memory<byte> destination, out int bytesWritten) => Flush(destination.Span, out bytesWritten);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,23 @@ public void InvalidWindow()
public void GetMaxCompressedSize_Basic()
{
Assert.Throws<ArgumentOutOfRangeException>("inputSize", () => BrotliEncoder.GetMaxCompressedLength(-1));
Assert.Throws<ArgumentOutOfRangeException>("inputSize", () => BrotliEncoder.GetMaxCompressedLength(2147483133));
Assert.InRange(BrotliEncoder.GetMaxCompressedLength(2147483132), 0, int.MaxValue);
Assert.Equal(1, BrotliEncoder.GetMaxCompressedLength(0));
Assert.Throws<ArgumentOutOfRangeException>("inputSize", () => BrotliEncoder.GetMaxCompressedLength(2_146_959_482));
Assert.InRange(BrotliEncoder.GetMaxCompressedLength(2_146_959_481), 0, int.MaxValue); // 2_146_959_481 produces int.MaxValue
Assert.Equal(2, BrotliEncoder.GetMaxCompressedLength(0));
}

[Fact]
public void DestinationBufferWithSizeEqualToMaxCompressedLength_ShouldAlwaysSucceed()
{
byte[] source = new byte[256000];
var rng = new Random(1234);
rng.NextBytes(source);

int maxLength = BrotliEncoder.GetMaxCompressedLength(source.Length);
var resultBuffer = new byte[maxLength];

Assert.True(BrotliEncoder.TryCompress(source, resultBuffer, out int bytesWritten, quality: 5, window: 10));
Assert.True(maxLength >= bytesWritten);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ EXPORTS
BrotliEncoderCreateInstance
BrotliEncoderDestroyInstance
BrotliEncoderHasMoreOutput
BrotliEncoderMaxCompressedSize
BrotliEncoderSetParameter
CompressionNative_Crc32
CompressionNative_Deflate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ BrotliEncoderCompressStream
BrotliEncoderCreateInstance
BrotliEncoderDestroyInstance
BrotliEncoderHasMoreOutput
BrotliEncoderMaxCompressedSize
BrotliEncoderSetParameter
CompressionNative_Crc32
CompressionNative_Deflate
Expand Down
1 change: 1 addition & 0 deletions src/native/libs/System.IO.Compression.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ static const Entry s_compressionNative[] =
DllImportEntry(BrotliEncoderCreateInstance)
DllImportEntry(BrotliEncoderDestroyInstance)
DllImportEntry(BrotliEncoderHasMoreOutput)
DllImportEntry(BrotliEncoderMaxCompressedSize)
DllImportEntry(BrotliEncoderSetParameter)
DllImportEntry(CompressionNative_Crc32)
DllImportEntry(CompressionNative_Deflate)
Expand Down
Loading