Skip to content

Commit

Permalink
Call native BrotliEncoderMaxCompressedSize method for BrotliEncoder.G…
Browse files Browse the repository at this point in the history
…etMaxCompressedLength (#108043)
  • Loading branch information
buyaa-n authored Oct 8, 2024
1 parent 9bfe7bf commit 848cabd
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 18 deletions.
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

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

0 comments on commit 848cabd

Please sign in to comment.