aboutsummaryrefslogtreecommitdiff
path: root/lib/Net.Compression/VNLib.Net.Compression
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Net.Compression/VNLib.Net.Compression')
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/CompressionExtensions.cs75
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/CompressorManager.cs59
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/INativeCompressionLib.cs66
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/INativeCompressor.cs79
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs33
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/NativeCompressionLib.cs141
-rw-r--r--lib/Net.Compression/VNLib.Net.Compression/SafeCompressorHandle.cs45
7 files changed, 446 insertions, 52 deletions
diff --git a/lib/Net.Compression/VNLib.Net.Compression/CompressionExtensions.cs b/lib/Net.Compression/VNLib.Net.Compression/CompressionExtensions.cs
new file mode 100644
index 0000000..0a4f7aa
--- /dev/null
+++ b/lib/Net.Compression/VNLib.Net.Compression/CompressionExtensions.cs
@@ -0,0 +1,75 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Compression
+* File: CompressionExtensions.cs
+*
+* CompressionExtensions.cs is part of VNLib.Net.Compression which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Compression is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Net.Compression is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Net.Compression. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Buffers;
+
+using VNLib.Net.Http;
+
+namespace VNLib.Net.Compression
+{
+ internal static class CompressionExtensions
+ {
+ /// <summary>
+ /// Compresses a block using the compressor context pointer provided
+ /// </summary>
+ /// <param name="nativeLib"></param>
+ /// <param name="comp">A pointer to the compressor context</param>
+ /// <param name="output">A buffer to write the result to</param>
+ /// <param name="input">The input block of memory to compress</param>
+ /// <param name="finalBlock">A value that indicates if a flush is requested</param>
+ /// <returns>The results of the compression operation</returns>
+ public static unsafe CompressionResult CompressBlock(this LibraryWrapper nativeLib, IntPtr comp, Memory<byte> output, ReadOnlyMemory<byte> input, bool finalBlock)
+ {
+ //get pointers to the input and output buffers
+ using MemoryHandle inPtr = input.Pin();
+ using MemoryHandle outPtr = output.Pin();
+
+ //Create the operation struct
+ CompressionOperation operation;
+ CompressionOperation* op = &operation;
+
+ op->flush = finalBlock ? 1 : 0;
+ op->bytesRead = 0;
+ op->bytesWritten = 0;
+
+ //Configure the input and output buffers
+ op->inputBuffer = inPtr.Pointer;
+ op->inputSize = input.Length;
+
+ op->outputBuffer = outPtr.Pointer;
+ op->outputSize = output.Length;
+
+ //Call the native compress function
+ nativeLib!.CompressBlock(comp, &operation);
+
+ //Return the number of bytes written
+ return new()
+ {
+ BytesRead = op->bytesRead,
+ BytesWritten = op->bytesWritten
+ };
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Compression/VNLib.Net.Compression/CompressorManager.cs b/lib/Net.Compression/VNLib.Net.Compression/CompressorManager.cs
index 5a86c62..bcc85c9 100644
--- a/lib/Net.Compression/VNLib.Net.Compression/CompressorManager.cs
+++ b/lib/Net.Compression/VNLib.Net.Compression/CompressorManager.cs
@@ -35,10 +35,10 @@
*/
using System;
-using System.Buffers;
using System.Text.Json;
using System.Diagnostics;
using System.IO.Compression;
+using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using VNLib.Net.Http;
@@ -46,6 +46,10 @@ using VNLib.Utils.Logging;
namespace VNLib.Net.Compression
{
+
+ /// <summary>
+ /// A compressor manager that implements the IHttpCompressorManager interface, for runtime loading.
+ /// </summary>
public sealed class CompressorManager : IHttpCompressorManager
{
const string NATIVE_LIB_NAME = "vnlib_compress.dll";
@@ -85,7 +89,7 @@ namespace VNLib.Net.Compression
log?.Debug("Attempting to load native compression library from: {lib}", libPath);
//Load the native library
- _nativeLib = LibraryWrapper.LoadLibrary(libPath);
+ _nativeLib = LibraryWrapper.LoadLibrary(libPath, DllImportSearchPath.SafeDirectories);
log?.Debug("Loaded native compression library with compression level {l}", _compLevel.ToString());
}
@@ -102,26 +106,17 @@ namespace VNLib.Net.Compression
}
///<inheritdoc/>
- public object AllocCompressor()
- {
- return new Compressor();
- }
+ public object AllocCompressor() => new Compressor();
///<inheritdoc/>
public int InitCompressor(object compressorState, CompressionMethod compMethod)
{
- //For now do not allow empty compression methods, later we should allow this to be used as a passthrough
- if(compMethod == CompressionMethod.None)
- {
- throw new ArgumentException("Compression method cannot be None", nameof(compMethod));
- }
-
Compressor compressor = Unsafe.As<Compressor>(compressorState) ?? throw new ArgumentNullException(nameof(compressorState));
//Instance should be null during initialization calls
Debug.Assert(compressor.Instance == IntPtr.Zero, "Init was called but and old compressor instance was not properly freed");
- //Alloc the compressor
+ //Alloc the compressor, let native lib raise exception for supported methods
compressor.Instance = _nativeLib!.AllocateCompressor(compMethod, _compLevel);
//Return the compressor block size
@@ -156,7 +151,7 @@ namespace VNLib.Net.Compression
}
//Force a flush until no more data is available
- CompressionResult result = CompressBlock(compressor.Instance, output, default, true);
+ CompressionResult result = _nativeLib.CompressBlock(compressor.Instance, output, default, true);
return result.BytesWritten;
}
@@ -171,41 +166,9 @@ namespace VNLib.Net.Compression
}
//Compress the block
- return CompressBlock(compressor.Instance, output, input, false);
+ return _nativeLib.CompressBlock(compressor.Instance, output, input, false);
}
-
- private unsafe CompressionResult CompressBlock(IntPtr comp, Memory<byte> output, ReadOnlyMemory<byte> input, bool finalBlock)
- {
- //get pointers to the input and output buffers
- using MemoryHandle inPtr = input.Pin();
- using MemoryHandle outPtr = output.Pin();
-
- //Create the operation struct
- CompressionOperation operation;
- CompressionOperation* op = &operation;
-
- op->flush = finalBlock ? 1 : 0;
- op->bytesRead = 0;
- op->bytesWritten = 0;
-
- //Configure the input and output buffers
- op->inputBuffer = inPtr.Pointer;
- op->inputSize = input.Length;
-
- op->outputBuffer = outPtr.Pointer;
- op->outputSize = output.Length;
-
- //Call the native compress function
- _nativeLib!.CompressBlock(comp, &operation);
-
- //Return the number of bytes written
- return new()
- {
- BytesRead = op->bytesRead,
- BytesWritten = op->bytesWritten
- };
- }
-
+
/*
* A class to contain the compressor state
diff --git a/lib/Net.Compression/VNLib.Net.Compression/INativeCompressionLib.cs b/lib/Net.Compression/VNLib.Net.Compression/INativeCompressionLib.cs
new file mode 100644
index 0000000..878dc5c
--- /dev/null
+++ b/lib/Net.Compression/VNLib.Net.Compression/INativeCompressionLib.cs
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Compression
+* File: INativeCompressionLib.cs
+*
+* INativeCompressionLib.cs is part of VNLib.Net.Compression which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Compression is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Net.Compression is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Net.Compression. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+
+using VNLib.Net.Http;
+
+namespace VNLib.Net.Compression
+{
+ /// <summary>
+ /// Represents a native compression library that can create native
+ /// compressor instances.
+ /// </summary>
+ public interface INativeCompressionLib
+ {
+ /// <summary>
+ /// Gets the compression methods supported by the underluing library
+ /// </summary>
+ /// <returns>The supported compression methods</returns>
+ CompressionMethod GetSupportedMethods();
+
+ /// <summary>
+ /// Allocates a new <see cref="INativeCompressor"/> implementation that allows for
+ /// compressing stream data.
+ /// </summary>
+ /// <param name="method">The desired <see cref="CompressionMethod"/>, must be a supported method</param>
+ /// <param name="level">The desired <see cref="CompressionLevel"/> to compress blocks with</param>
+ /// <returns>The new <see cref="INativeCompressor"/></returns>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="NotSupportedException">The the level or method are not supported by the underlying library</exception>
+ INativeCompressor AllocCompressor(CompressionMethod method, CompressionLevel level);
+
+ /// <summary>
+ /// Allocates a safe compressor handle to allow native operations if preferred.
+ /// </summary>
+ ///<param name="method">The desired <see cref="CompressionMethod"/>, must be a supported method</param>
+ /// <param name="level">The desired <see cref="CompressionLevel"/> to compress blocks with</param>
+ /// <returns>A new <see cref="SafeHandle"/> that holds a pointer to the native compressor context</returns>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="NotSupportedException">The the level or method are not supported by the underlying library</exception>
+ SafeHandle AllocSafeCompressorHandle(CompressionMethod method, CompressionLevel level);
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Compression/VNLib.Net.Compression/INativeCompressor.cs b/lib/Net.Compression/VNLib.Net.Compression/INativeCompressor.cs
new file mode 100644
index 0000000..3455ea0
--- /dev/null
+++ b/lib/Net.Compression/VNLib.Net.Compression/INativeCompressor.cs
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Compression
+* File: INativeCompressor.cs
+*
+* INativeCompressor.cs is part of VNLib.Net.Compression which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Compression is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Net.Compression is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Net.Compression. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.IO.Compression;
+
+using VNLib.Net.Http;
+
+namespace VNLib.Net.Compression
+{
+ /// <summary>
+ /// Represents a native compressor instance
+ /// </summary>
+ public interface INativeCompressor : IDisposable
+ {
+ /// <summary>
+ /// Gets the underlying compressor type
+ /// </summary>
+ /// <returns>The underlying compressor type</returns>
+ CompressionMethod GetCompressionMethod();
+
+ /// <summary>
+ /// Gets the underlying compressor's compression level
+ /// </summary>
+ /// <returns>The configured <see cref="CompressionLevel"/> of the current compressor</returns>
+ CompressionLevel GetCompressionLevel();
+
+ /// <summary>
+ /// Flushes all remaining data in the compressor to the output buffer
+ /// </summary>
+ /// <param name="buffer">The output buffer to write flushed compressor data to</param>
+ /// <returns>The number of bytes written to the output buffer</returns>
+ int Flush(Memory<byte> buffer);
+
+ /// <summary>
+ /// Compresses the input block and writes the compressed data to the output block
+ /// </summary>
+ /// <param name="input">The input buffer to compress</param>
+ /// <param name="bytesRead">The number of bytes read by the compressor</param>
+ /// <param name="output">The output buffer to write compressed data to</param>
+ /// <param name="bytesWritten">The number of bytes written to the output buffer</param>
+ CompressionResult Compress(ReadOnlyMemory<byte> input, Memory<byte> output);
+
+ /// <summary>
+ /// Gets the compressor block size if configured
+ /// </summary>
+ /// <returns>The ideal input buffer size for compressing blocks, or <![CDATA[<1]]> if block size is unlimited</returns>
+ int GetBlockSize();
+
+ /// <summary>
+ /// Determines the maximum number of output bytes for the given number of input bytes
+ /// specified by the size parameter
+ /// </summary>
+ /// <param name="size">The number of bytes to get the compressed size of</param>
+ /// <returns>The maxium size of the compressed data</returns>
+ int GetCompressedSize(int size);
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs b/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
index 0f86107..2ee6018 100644
--- a/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
+++ b/lib/Net.Compression/VNLib.Net.Compression/LibraryWrapper.cs
@@ -85,10 +85,10 @@ namespace VNLib.Net.Compression
/// and used for the lifetime of the application.
/// </para>
/// </summary>
- internal sealed class LibraryWrapper
+ internal sealed class LibraryWrapper
{
private readonly SafeLibraryHandle _lib;
- private readonly MethodTable _methodTable;
+ private MethodTable _methodTable;
public string LibFilePath { get; }
@@ -104,10 +104,10 @@ namespace VNLib.Net.Compression
/// </summary>
/// <param name="filePath">The path to the native library to load</param>
/// <returns>The native library wrapper</returns>
- public static LibraryWrapper LoadLibrary(string filePath)
+ public static LibraryWrapper LoadLibrary(string filePath, DllImportSearchPath searchType)
{
//Load the library into the current process
- SafeLibraryHandle lib = SafeLibraryHandle.LoadLibrary(filePath, DllImportSearchPath.SafeDirectories);
+ SafeLibraryHandle lib = SafeLibraryHandle.LoadLibrary(filePath, searchType);
try
{
@@ -223,6 +223,14 @@ namespace VNLib.Net.Compression
}
/// <summary>
+ /// Frees the specified compressor instance without raising exceptions
+ /// </summary>
+ /// <param name="compressor">A pointer to the valid compressor instance to free</param>
+ /// <returns>A value indicating the result of the free operation</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int FreeSafeCompressor(IntPtr compressor) => _methodTable.Free(compressor);
+
+ /// <summary>
/// Determines the output size of a given input size and flush mode for the specified compressor
/// </summary>
/// <param name="compressor">A pointer to the compressor instance</param>
@@ -255,6 +263,23 @@ namespace VNLib.Net.Compression
return result;
}
+ ///<inheritdoc/>
+ ~LibraryWrapper()
+ {
+ _methodTable = default;
+ _lib.Dispose();
+ }
+
+ /// <summary>
+ /// Manually releases the library
+ /// </summary>
+ internal void ManualRelease()
+ {
+ _methodTable = default;
+ _lib.Dispose();
+ GC.SuppressFinalize(this);
+ }
+
private readonly struct MethodTable
{
public GetSupportedMethodsDelegate GetMethods { get; init; }
diff --git a/lib/Net.Compression/VNLib.Net.Compression/NativeCompressionLib.cs b/lib/Net.Compression/VNLib.Net.Compression/NativeCompressionLib.cs
new file mode 100644
index 0000000..f5b9071
--- /dev/null
+++ b/lib/Net.Compression/VNLib.Net.Compression/NativeCompressionLib.cs
@@ -0,0 +1,141 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Compression
+* File: NativeCompressionLib.cs
+*
+* NativeCompressionLib.cs is part of VNLib.Net.Compression which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Compression is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Net.Compression is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Net.Compression. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+
+using VNLib.Net.Http;
+using VNLib.Utils;
+using VNLib.Utils.Extensions;
+
+namespace VNLib.Net.Compression
+{
+ /// <summary>
+ /// A referrence native compression library implementation. Allows for creating compressor instances
+ /// from a native dll.
+ /// </summary>
+ public sealed class NativeCompressionLib : VnDisposeable, INativeCompressionLib
+ {
+ private readonly LibraryWrapper _library;
+
+ private NativeCompressionLib(LibraryWrapper nativeLib) => _library = nativeLib;
+
+ ///<inheritdoc/>
+ protected override void Free() => _library.ManualRelease();
+
+ /// <summary>
+ /// Loads the native compression DLL at the specified file path and search pattern
+ /// </summary>
+ /// <param name="libPath">The path (relative or absolute) path to the native dll to load</param>
+ /// <param name="searchPath">The dll search pattern</param>
+ /// <returns>A new <see cref="NativeCompressionLib"/> library handle</returns>
+ public static NativeCompressionLib LoadLibrary(string libPath, DllImportSearchPath searchPath)
+ {
+ LibraryWrapper wrapper = LibraryWrapper.LoadLibrary(libPath, searchPath);
+ return new NativeCompressionLib(wrapper);
+ }
+
+ ///<inheritdoc/>
+ ///<exception cref="NativeCompressionException"></exception>
+ public CompressionMethod GetSupportedMethods() => _library.GetSupportedMethods();
+
+ ///<inheritdoc/>
+ ///<exception cref="NativeCompressionException"></exception>
+ public INativeCompressor AllocCompressor(CompressionMethod method, CompressionLevel level)
+ {
+#pragma warning disable CA2000 // Dispose objects before losing scope
+
+ SafeHandle libHandle = AllocSafeCompressorHandle(method, level);
+ return new Compressor(_library, libHandle);
+
+#pragma warning restore CA2000 // Dispose objects before losing scope
+ }
+
+ ///<inheritdoc/>
+ ///<exception cref="NativeCompressionException"></exception>
+ public SafeHandle AllocSafeCompressorHandle(CompressionMethod method, CompressionLevel level)
+ {
+ //Alloc compressor then craete a safe handle
+ IntPtr comp = _library.AllocateCompressor(method, level);
+ return new SafeCompressorHandle(_library, comp);
+ }
+
+ internal sealed record class Compressor(LibraryWrapper LibComp, SafeHandle Handle) : INativeCompressor
+ {
+
+ ///<inheritdoc/>
+ public CompressionResult Compress(ReadOnlyMemory<byte> input, Memory<byte> output)
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ return LibComp.CompressBlock(compressor, output, input, false);
+ }
+
+ ///<inheritdoc/>
+ public void Dispose() => Handle.Dispose();
+
+ ///<inheritdoc/>
+ public int Flush(Memory<byte> buffer)
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ CompressionResult result = LibComp.CompressBlock(compressor, buffer, ReadOnlyMemory<byte>.Empty, true);
+ return result.BytesWritten;
+ }
+
+ ///<inheritdoc/>
+ public int GetBlockSize()
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ return LibComp.GetBlockSize(compressor);
+ }
+
+ ///<inheritdoc/>
+ public int GetCompressedSize(int size)
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ return LibComp.GetOutputSize(compressor, size, 1);
+ }
+
+ ///<inheritdoc/>
+ public CompressionLevel GetCompressionLevel()
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ return LibComp.GetCompressorLevel(compressor);
+ }
+
+ ///<inheritdoc/>
+ public CompressionMethod GetCompressionMethod()
+ {
+ Handle.ThrowIfClosed();
+ IntPtr compressor = Handle.DangerousGetHandle();
+ return LibComp.GetCompressorType(compressor);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Net.Compression/VNLib.Net.Compression/SafeCompressorHandle.cs b/lib/Net.Compression/VNLib.Net.Compression/SafeCompressorHandle.cs
new file mode 100644
index 0000000..4c21b6b
--- /dev/null
+++ b/lib/Net.Compression/VNLib.Net.Compression/SafeCompressorHandle.cs
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Net.Compression
+* File: SafeCompressorHandle.cs
+*
+* SafeCompressorHandle.cs is part of VNLib.Net.Compression which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Net.Compression is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Net.Compression is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Net.Compression. If not, see http://www.gnu.org/licenses/.
+*/
+
+
+using System;
+
+using Microsoft.Win32.SafeHandles;
+
+namespace VNLib.Net.Compression
+{
+ internal sealed class SafeCompressorHandle : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ private readonly LibraryWrapper _library;
+
+ internal SafeCompressorHandle(LibraryWrapper libComp, IntPtr compressor): base(true)
+ {
+ _library = libComp;
+ SetHandle(compressor);
+ }
+
+ ///<inheritdoc/>
+ protected override bool ReleaseHandle() => _library.FreeSafeCompressor(handle) > 0;
+ }
+} \ No newline at end of file