Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion BrotliSharpLib.Tests/BrotliSharpLib.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
<TargetFrameworks>net6.0</TargetFrameworks>
<ApplicationIcon />
<OutputTypeEx>library</OutputTypeEx>
<StartupObject />
Expand Down
137 changes: 137 additions & 0 deletions BrotliSharpLib/Brotli.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,64 @@ public static unsafe byte[] DecompressBuffer(byte[] buffer, int offset, int leng
}
}

#if HAS_SPAN
/// <summary>
/// Attempts to decompress the compressed data in <paramref name="buffer"/> into <paramref name="outBufferData"/>.
/// </summary>
/// <param name="buffer">The buffer containing compressed data.</param>
/// <param name="outBufferData">The buffer to write the decompressed data to.</param>
/// <param name="writtenData">The number of bytes written to the output buffer.</param>
/// <param name="customDict">The custom dictionary that will be passed to the decoder.</param>
/// <returns><see langword="true"/> if the input buffer was successfully decompressed, <see langword="false"/> otherwise.</returns>
public static unsafe bool TryDecompressBuffer(ReadOnlySpan<byte> buffer, Span<byte> outBufferData, out int writtenData, ReadOnlySpan<byte> customDict = default)
{
// Create the decoder state and intialise it.
var s = BrotliCreateDecoderState();
BrotliDecoderStateInit(ref s);

writtenData = 0;

// Set the custom dictionary
fixed (byte* customDictPtr = customDict)
{
if (customDictPtr != null)
BrotliDecoderSetCustomDictionary(ref s, customDict.Length, customDictPtr);

// Pin the output buffer and the input buffer.
fixed (byte* outBuffer = outBufferData)
{
fixed (byte* inBuffer = buffer)
{
// Specify the length of the input buffer.
size_t len = buffer.Length;

// Local vars for input/output buffer.
var bufPtr = inBuffer;
var outPtr = outBuffer;

// Specify the amount of bytes available in the output buffer.
size_t availOut = outBufferData.Length;

// Total number of bytes decoded.
size_t total = 0;

// Main decompression loop.
var result = BrotliDecoderDecompressStream(ref s, &len, &bufPtr, &availOut, &outPtr, &total);

// Cleanup and throw.
BrotliDecoderStateCleanup(ref s);

if (result != BrotliDecoderResult.BROTLI_DECODER_RESULT_SUCCESS)
return false;

writtenData = outBufferData.Length - (int)availOut;
return true;
}
}
}
}
#endif

/// <summary>
/// Compresses a byte array into a new byte array using brotli.
/// </summary>
Expand Down Expand Up @@ -167,5 +225,84 @@ public static unsafe byte[] CompressBuffer(byte[] buffer, int offset, int length
return ms.ToArray();
}
}

#if HAS_SPAN
/// <summary>
/// Tries to compress <paramref name="buffer"/> into <paramref name="outBuffer"/>.
/// </summary>
/// <param name="buffer">The buffer to read uncompressed data from.</param>
/// <param name="outBuffer">The buffer to write compressed data to.</param>
/// <param name="writtenData">The amount of data written to <paramref name="outBuffer"/>.</param>
/// <param name="customDict">The custom dictionary that will be passed to the encoder.</param>
/// <returns><see langword="true"/> if the input buffer was successfully compressed, <see langword="false"/> otherwise.</returns>
public static bool TryCompressBuffer(ReadOnlySpan<byte> buffer, Span<byte> outBuffer, out int writtenData, ReadOnlySpan<byte> customDict = default)
=> TryCompressBuffer(buffer, outBuffer, out writtenData, customDict);
/// <summary>
/// Tries to compress <paramref name="buffer"/> into <paramref name="outBuffer"/>.
/// </summary>
/// <param name="buffer">The buffer to read uncompressed data from.</param>
/// <param name="outBuffer">The buffer to write compressed data to.</param>
/// <param name="writtenData">The amount of data written to <paramref name="outBuffer"/>.</param>
/// <param name="quality">The quality of the compression. This must be a value between 0 to 11 (inclusive).</param>
/// <param name="lgwin">The window size (in bits). This must be a value between 10 and 24 (inclusive).</param>
/// <param name="customDict">The custom dictionary that will be passed to the encoder.</param>
/// <returns><see langword="true"/> if the input buffer was successfully compressed, <see langword="false"/> otherwise.</returns>
public static unsafe bool TryCompressBuffer(ReadOnlySpan<byte> buffer, Span<byte> outBuffer, out int writtenData,
int quality, int lgwin, ReadOnlySpan<byte> customDict = default)
{
// Create the encoder state and intialise it.
var s = BrotliEncoderCreateInstance(null, null, null);

// Set the encoder parameters
if (quality != -1)
BrotliEncoderSetParameter(ref s, BrotliEncoderParameter.BROTLI_PARAM_QUALITY, (uint)quality);

if (lgwin != -1)
BrotliEncoderSetParameter(ref s, BrotliEncoderParameter.BROTLI_PARAM_LGWIN, (uint)lgwin);

// Set the custom dictionary
fixed (byte* cd = customDict)
{
if (cd != null)
BrotliEncoderSetCustomDictionary(ref s, customDict.Length, cd);
}

writtenData = 0;

size_t available_in = buffer.Length;
size_t available_out = outBuffer.Length;
fixed (byte* o = outBuffer)
fixed (byte* b = buffer)
{
byte* next_in = b;
byte* next_out = o;

bool fail = false;

// Compress stream using inputted buffer
if (!BrotliEncoderCompressStream(ref s, BrotliEncoderOperation.BROTLI_OPERATION_FINISH,
&available_in, &next_in, &available_out, &next_out, null))
{
fail = true;
}
else
{
// Check that the encoder is finished
if (BrotliEncoderIsFinished(ref s))
{
fail = true;
}
}

BrotliEncoderDestroyInstance(ref s);

if (fail)
return false;
}

writtenData = outBuffer.Length - (int)available_out;
return true;
}
#endif
}
}
36 changes: 27 additions & 9 deletions BrotliSharpLib/BrotliSharpLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
<NoWarn>1570;1701</NoWarn>
</PropertyGroup>
<PropertyGroup>
<Version>0.3.3</Version>
<FileVersion>0.3.3</FileVersion>
<Version>0.3.4</Version>
<FileVersion>0.3.4</FileVersion>
<Authors>master131</Authors>
<Description>Full C# port of Brotli compression library.</Description>
<Copyright>Copyright (c) 2017-2019 master131</Copyright>
<RepositoryUrl>https://github.com/master131/BrotliSharpLib</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<RepositoryType>git</RepositoryType>
<PackageTags>brotli;csharp;net</PackageTags>
<AssemblyVersion>0.3.2</AssemblyVersion>
<AssemblyVersion>0.3.4</AssemblyVersion>
<PackageLicenseUrl>https://github.com/master131/BrotliSharpLib/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/master131/BrotliSharpLib</PackageProjectUrl>
<SignAssembly>true</SignAssembly>
Expand All @@ -29,37 +29,55 @@
<PropertyGroup Condition="'$(TargetFramework)'!='net20' AND '$(TargetFramework)'!='net35' AND '$(TargetFramework)'!='net40' AND '$(TargetFramework)'!='net45' AND '$(TargetFramework)'!='netstandard1.1'">
<DefineConstants>$(DefineConstants);SIZE_OF_T</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='net20' AND '$(TargetFramework)'!='net35' AND '$(TargetFramework)'!='net40'">
<DefineConstants>$(DefineConstants);HAS_SPAN</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.1'">
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
<PackageReference Include="System.IO.Compression">
<Version>4.3.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net451'">
<PackageReference Include="System.Memory">
<Version>4.5.4</Version>
</PackageReference>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<PackageReference Include="System.Runtime.CompilerServices.Unsafe">
<Version>4.5.2</Version>
<Version>4.5.3</Version>
</PackageReference>
</ItemGroup>
</Project>