< Summary

Information
Class: System.IO.Compression.ZstandardEncoder
Assembly: System.IO.Compression
File(s): D:\runner\runtime\src\libraries\System.IO.Compression\src\System\IO\Compression\Zstandard\ZstandardEncoder.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 267
Coverable lines: 267
Total lines: 497
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 58
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
.ctor(...)0%220%
.ctor(...)100%110%
.ctor(...)0%440%
.ctor(...)0%220%
.ctor(...)0%10100%
InitializeEncoder()0%220%
Compress(...)0%660%
Flush(...)100%110%
CompressCore(...)0%880%
GetMaxCompressedLength(...)0%440%
TryCompress(...)100%110%
TryCompress(...)100%110%
TryCompress(...)100%110%
TryCompressCore(...)0%880%
Reset()100%110%
SetPrefix(...)0%440%
SetSourceLength(...)0%440%
Dispose()100%110%
EnsureNotDisposed()100%110%
SetQuality(...)0%220%
SetWindowLog(...)0%220%
SetDictionary(...)100%110%
SetParameter(...)100%110%

File(s)

D:\runner\runtime\src\libraries\System.IO.Compression\src\System\IO\Compression\Zstandard\ZstandardEncoder.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Runtime.InteropServices;
 8using Microsoft.Win32.SafeHandles;
 9
 10namespace System.IO.Compression
 11{
 12    /// <summary>Provides methods and properties to compress data using Zstandard compression.</summary>
 13    [System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
 14    [System.Runtime.Versioning.UnsupportedOSPlatform("wasi")]
 15    public sealed class ZstandardEncoder : IDisposable
 16    {
 17        internal SafeZstdCompressHandle _context;
 18        private bool _disposed;
 19
 20        /// <summary>
 21        /// True if we finished compressing the entire input.
 22        /// </summary>
 23        private bool _finished;
 24
 25        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with default settings.</summ
 26        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 027        public ZstandardEncoder()
 028        {
 029            _disposed = false;
 030            InitializeEncoder();
 031        }
 32
 33        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with the specified quality l
 34        /// <param name="quality">The compression quality level.</param>
 35        /// <exception cref="ArgumentOutOfRangeException"><paramref name="quality"/> is not between the minimum and maxi
 36        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 037        public ZstandardEncoder(int quality)
 038        {
 039            _disposed = false;
 040            InitializeEncoder();
 41
 42            try
 043            {
 044                if (quality != 0)
 045                {
 046                    SetQuality(_context, quality);
 047                }
 048            }
 049            catch
 050            {
 051                _context.Dispose();
 052                throw;
 53            }
 054        }
 55
 56        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with the specified dictionar
 57        /// <param name="dictionary">The compression dictionary to use.</param>
 58        /// <exception cref="ArgumentNullException"><paramref name="dictionary"/> is null.</exception>
 59        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 060        public ZstandardEncoder(ZstandardDictionary dictionary)
 061        {
 062            _disposed = false;
 063            InitializeEncoder();
 64
 65            try
 066            {
 067                SetDictionary(dictionary);
 068            }
 069            catch
 070            {
 071                _context.Dispose();
 072                throw;
 73            }
 074        }
 75
 76        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with the specified quality a
 77        /// <param name="quality">The compression quality level.</param>
 78        /// <param name="windowLog2">The base-2 logarithm of the window size for compression.</param>
 79        /// <exception cref="ArgumentOutOfRangeException"><paramref name="quality"/> is not between the minimum and maxi
 80        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 081        public ZstandardEncoder(int quality, int windowLog2)
 082        {
 083            _disposed = false;
 084            InitializeEncoder();
 85
 86            try
 087            {
 088                if (quality != 0)
 089                {
 090                    SetQuality(_context, quality);
 091                }
 092                if (windowLog2 != 0)
 093                {
 094                    SetWindowLog(_context, windowLog2);
 095                }
 096            }
 097            catch
 098            {
 099                _context.Dispose();
 0100                throw;
 101            }
 0102        }
 103
 104        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with the specified dictionar
 105        /// <param name="dictionary">The compression dictionary to use.</param>
 106        /// <param name="windowLog2">The base-2 logarithm of the window size for compression.</param>
 107        /// <exception cref="ArgumentNullException"><paramref name="dictionary"/> is null.</exception>
 108        /// <exception cref="ArgumentOutOfRangeException"><paramref name="windowLog2"/> is not between the minimum and m
 109        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 0110        public ZstandardEncoder(ZstandardDictionary dictionary, int windowLog2)
 0111        {
 0112            ArgumentNullException.ThrowIfNull(dictionary);
 113
 0114            _disposed = false;
 0115            InitializeEncoder();
 116
 117            try
 0118            {
 0119                SetDictionary(dictionary);
 120
 0121                if (windowLog2 != 0)
 0122                {
 0123                    SetWindowLog(_context, windowLog2);
 0124                }
 0125            }
 0126            catch
 0127            {
 0128                _context.Dispose();
 0129                throw;
 130            }
 0131        }
 132
 133        /// <summary>Initializes a new instance of the <see cref="ZstandardEncoder"/> class with the specified compressi
 134        /// <param name="compressionOptions">The compression options to use.</param>
 135        /// <exception cref="ArgumentNullException"><paramref name="compressionOptions"/> is null.</exception>
 136        /// <exception cref="ArgumentOutOfRangeException">A parameter from <paramref name="compressionOptions"/> is not 
 137        /// <exception cref="IOException">Failed to create the <see cref="ZstandardEncoder"/> instance.</exception>
 0138        public ZstandardEncoder(ZstandardCompressionOptions compressionOptions)
 0139        {
 0140            ArgumentNullException.ThrowIfNull(compressionOptions);
 141
 0142            _disposed = false;
 0143            InitializeEncoder();
 144
 145            try
 0146            {
 0147                if (compressionOptions.Dictionary is not null)
 0148                {
 0149                    SetDictionary(compressionOptions.Dictionary);
 0150                }
 151                else
 0152                {
 0153                    SetQuality(_context, compressionOptions.Quality);
 0154                }
 155
 0156                if (compressionOptions.WindowLog2 != 0)
 0157                {
 0158                    SetWindowLog(_context, compressionOptions.WindowLog2);
 0159                }
 160
 0161                if (compressionOptions.AppendChecksum)
 0162                {
 0163                    SetParameter(_context, Interop.Zstd.ZstdCParameter.ZSTD_c_checksumFlag, 1);
 0164                }
 165
 0166                if (compressionOptions.EnableLongDistanceMatching)
 0167                {
 0168                    SetParameter(_context, Interop.Zstd.ZstdCParameter.ZSTD_c_enableLongDistanceMatching, 1);
 0169                }
 170
 0171                if (compressionOptions.TargetBlockSize != 0)
 0172                {
 0173                    SetParameter(_context, Interop.Zstd.ZstdCParameter.ZSTD_c_targetCBlockSize, compressionOptions.Targe
 0174                }
 0175            }
 0176            catch
 0177            {
 0178                _context.Dispose();
 0179                throw;
 180            }
 0181        }
 182
 183        [MemberNotNull(nameof(_context))]
 184        private void InitializeEncoder()
 0185        {
 0186            _context = Interop.Zstd.ZSTD_createCCtx();
 0187            if (_context.IsInvalid)
 0188            {
 0189                throw new OutOfMemoryException();
 190            }
 0191        }
 192
 193        /// <summary>Compresses the specified data.</summary>
 194        /// <param name="source">The data to compress.</param>
 195        /// <param name="destination">The buffer to write the compressed data to.</param>
 196        /// <param name="bytesConsumed">When this method returns, contains the number of bytes consumed from the source.
 197        /// <param name="bytesWritten">When this method returns, contains the number of bytes written to the destination
 198        /// <param name="isFinalBlock"><see langword="true" /> if this is the final block of data to compress.</param>
 199        /// <returns>An <see cref="OperationStatus"/> indicating the result of the operation.</returns>
 200        /// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
 201        /// <exception cref="IOException">An error occurred during compression.</exception>
 202        public OperationStatus Compress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesConsumed, out in
 0203        {
 0204            EnsureNotDisposed();
 205
 0206            bytesConsumed = 0;
 0207            bytesWritten = 0;
 208
 0209            if (source.IsEmpty && !isFinalBlock)
 0210            {
 0211                return OperationStatus.Done;
 212            }
 213
 0214            return CompressCore(source, destination, out bytesConsumed, out bytesWritten,
 0215                isFinalBlock ? Interop.Zstd.ZstdEndDirective.ZSTD_e_end : Interop.Zstd.ZstdEndDirective.ZSTD_e_continue)
 0216        }
 217
 218        /// <summary>Flushes any remaining processed data to the destination buffer.</summary>
 219        /// <param name="destination">The buffer to write the flushed data to.</param>
 220        /// <param name="bytesWritten">When this method returns, contains the number of bytes written to the destination
 221        /// <returns>An <see cref="OperationStatus"/> indicating the result of the operation.</returns>
 222        /// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
 223        /// <exception cref="IOException">An error occurred during the operation.</exception>
 224        public OperationStatus Flush(Span<byte> destination, out int bytesWritten)
 0225        {
 0226            EnsureNotDisposed();
 227
 0228            return CompressCore(ReadOnlySpan<byte>.Empty, destination, out _, out bytesWritten,
 0229                Interop.Zstd.ZstdEndDirective.ZSTD_e_flush);
 0230        }
 231
 232        private OperationStatus CompressCore(ReadOnlySpan<byte> source, Span<byte> destination,
 233            out int bytesConsumed, out int bytesWritten, Interop.Zstd.ZstdEndDirective endDirective)
 0234        {
 0235            bytesConsumed = 0;
 0236            bytesWritten = 0;
 237
 238            unsafe
 0239            {
 0240                fixed (byte* inBytes = &MemoryMarshal.GetReference(source))
 0241                fixed (byte* outBytes = &MemoryMarshal.GetReference(destination))
 0242                {
 0243                    var input = new Interop.Zstd.ZstdInBuffer
 0244                    {
 0245                        src = inBytes,
 0246                        size = (nuint)source.Length,
 0247                        pos = 0
 0248                    };
 249
 0250                    var output = new Interop.Zstd.ZstdOutBuffer
 0251                    {
 0252                        dst = outBytes,
 0253                        size = (nuint)destination.Length,
 0254                        pos = 0
 0255                    };
 256
 0257                    nuint result = Interop.Zstd.ZSTD_compressStream2(_context, ref output, ref input, endDirective);
 258
 0259                    if (ZstandardUtils.IsError(result, out var error))
 0260                    {
 0261                        if (error == Interop.Zstd.ZSTD_error.srcSize_wrong)
 0262                        {
 0263                            return OperationStatus.InvalidData;
 264                        }
 265
 0266                        ZstandardUtils.Throw(error);
 267                    }
 268
 0269                    bytesConsumed = (int)input.pos;
 0270                    bytesWritten = (int)output.pos;
 271
 0272                    if (input.pos == input.size)
 0273                    {
 0274                        _finished |= endDirective == Interop.Zstd.ZstdEndDirective.ZSTD_e_end;
 275
 0276                        return result == 0 ? OperationStatus.Done : OperationStatus.DestinationTooSmall;
 277                    }
 278                    else
 0279                    {
 0280                        return OperationStatus.DestinationTooSmall;
 281                    }
 282                }
 283            }
 0284        }
 285
 286        /// <summary>Gets the maximum compressed size for the specified input length.</summary>
 287        /// <param name="inputLength">The length of the input data.</param>
 288        /// <returns>The maximum possible compressed size.</returns>
 289        /// <exception cref="ArgumentOutOfRangeException"><paramref name="inputLength"/> is less than 0.</exception>
 290        public static long GetMaxCompressedLength(long inputLength)
 0291        {
 0292            ArgumentOutOfRangeException.ThrowIfNegative(inputLength);
 0293            ArgumentOutOfRangeException.ThrowIfGreaterThan(inputLength, nint.MaxValue);
 294
 0295            nuint result = Interop.Zstd.ZSTD_compressBound((nuint)inputLength);
 0296            if (ZstandardUtils.IsError(result))
 0297            {
 0298                throw new ArgumentOutOfRangeException(nameof(inputLength));
 299            }
 300
 0301            if (result > long.MaxValue)
 0302            {
 0303                throw new ArgumentOutOfRangeException(nameof(inputLength));
 304            }
 305
 0306            return (long)result;
 0307        }
 308
 309        /// <summary>Attempts to compress the specified data.</summary>
 310        /// <param name="source">The data to compress.</param>
 311        /// <param name="destination">The buffer to write the compressed data to.</param>
 312        /// <param name="bytesWritten">When this method returns <see langword="true" />, contains the number of bytes wr
 313        /// <returns><see langword="true" /> on success; <see langword="false" /> if the destination buffer is too small
 314        public static bool TryCompress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
 0315        {
 0316            return TryCompress(source, destination, out bytesWritten, ZstandardUtils.Quality_Default, 0);
 0317        }
 318
 319        /// <summary>Attempts to compress the specified data with the specified quality and window size.</summary>
 320        /// <param name="source">The data to compress.</param>
 321        /// <param name="destination">The buffer to write the compressed data to.</param>
 322        /// <param name="bytesWritten">When this method returns <see langword="true" />, contains the number of bytes wr
 323        /// <param name="quality">The compression quality level.</param>
 324        /// <param name="windowLog2">The base-2 logarithm of the window size for compression.</param>
 325        /// <returns><see langword="true" /> on success; <see langword="false" /> if the destination buffer is too small
 326        /// <exception cref="ArgumentOutOfRangeException"><paramref name="quality"/> or <paramref name="windowLog2"/> is
 327        public static bool TryCompress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten, int qual
 0328        {
 0329            return TryCompressCore(source, destination, out bytesWritten, quality, windowLog2, null);
 0330        }
 331
 332        /// <summary>Attempts to compress the specified data with the specified dictionary and window size.</summary>
 333        /// <param name="source">The data to compress.</param>
 334        /// <param name="destination">The buffer to write the compressed data to.</param>
 335        /// <param name="bytesWritten">When this method returns <see langword="true" />, contains the number of bytes wr
 336        /// <param name="dictionary">The compression dictionary to use.</param>
 337        /// <param name="windowLog2">The base-2 logarithm of the window size for compression.</param>
 338        /// <returns><see langword="true" /> on success; <see langword="false" /> if the destination buffer is too small
 339        /// <exception cref="ArgumentNullException"><paramref name="dictionary"/> is null.</exception>
 340        /// <exception cref="ArgumentOutOfRangeException"><paramref name="windowLog2"/> is out of the valid range.</exce
 341        public static bool TryCompress(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten, Zstandar
 0342        {
 0343            ArgumentNullException.ThrowIfNull(dictionary);
 0344            return TryCompressCore(source, destination, out bytesWritten, 0, windowLog2, dictionary);
 0345        }
 346
 347        internal static bool TryCompressCore(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten, in
 0348        {
 0349            bytesWritten = 0;
 350
 0351            using SafeZstdCompressHandle ctx = Interop.Zstd.ZSTD_createCCtx();
 0352            if (ctx.IsInvalid)
 0353            {
 0354                throw new OutOfMemoryException();
 355            }
 356
 0357            if (dictionary != null)
 0358            {
 0359                ctx.SetDictionary(dictionary.CompressionDictionary);
 0360            }
 361            else
 0362            {
 0363                SetQuality(ctx, quality);
 0364            }
 365
 0366            if (windowLog2 != 0)
 0367            {
 0368                SetWindowLog(ctx, windowLog2);
 0369            }
 370
 371            unsafe
 0372            {
 0373                fixed (byte* inBytes = &MemoryMarshal.GetReference(source))
 0374                fixed (byte* outBytes = &MemoryMarshal.GetReference(destination))
 0375                {
 0376                    nuint result = Interop.Zstd.ZSTD_compress2(ctx, outBytes, (nuint)destination.Length, inBytes, (nuint
 377
 0378                    if (ZstandardUtils.IsError(result, out var error))
 0379                    {
 0380                        return false;
 381                    }
 382
 0383                    bytesWritten = (int)result;
 0384                    return true;
 385                }
 386            }
 0387        }
 388
 389        /// <summary>Resets the encoder session, allowing reuse for the next compression operation.</summary>
 390        /// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
 391        /// <exception cref="IOException">Failed to reset the encoder session.</exception>
 392        public void Reset()
 0393        {
 0394            EnsureNotDisposed();
 395
 0396            _finished = false;
 0397            _context.Reset();
 0398        }
 399
 400        /// <summary>References a prefix for the next compression operation.</summary>
 401        /// <remarks>The prefix will be used only for the next compression frame and will be removed when <see cref="Res
 402        /// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
 403        /// <exception cref="InvalidOperationException">The encoder is in an invalid state for setting a prefix.</except
 404        public void SetPrefix(ReadOnlyMemory<byte> prefix)
 0405        {
 0406            EnsureNotDisposed();
 407
 0408            if (_finished)
 0409            {
 0410                throw new InvalidOperationException(SR.ZstandardEncoderDecoder_InvalidState);
 411            }
 412
 0413            nuint result = _context.SetPrefix(prefix);
 414
 0415            if (ZstandardUtils.IsError(result, out var error))
 0416            {
 0417                ZstandardUtils.Throw(error);
 418            }
 0419        }
 420
 421        /// <summary>Sets the length of the uncompressed data for the next compression operation.</summary>
 422        /// <param name="length">The length of the source data in bytes.</param>
 423        /// <remarks>
 424        /// Setting the source length is optional. If set, the information is stored in the header of the compressed dat
 425        /// Calling <see cref="Reset"/> clears the length. The length is validated during compression and if the value i
 426        /// the operation status is <see cref="OperationStatus.InvalidData"/>.
 427        /// </remarks>
 428        /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is negative.</exception>
 429        /// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
 430        public void SetSourceLength(long length)
 0431        {
 0432            ArgumentOutOfRangeException.ThrowIfNegative(length);
 433
 0434            EnsureNotDisposed();
 435
 0436            if (_finished)
 0437            {
 0438                throw new InvalidOperationException(SR.ZstandardEncoderDecoder_InvalidState);
 439            }
 440
 0441            if (ZstandardUtils.IsError(Interop.Zstd.ZSTD_CCtx_setPledgedSrcSize(_context, (ulong)length), out var error)
 0442            {
 0443                ZstandardUtils.Throw(error);
 444            }
 0445        }
 446
 447        /// <summary>Releases all resources used by the <see cref="ZstandardEncoder"/>.</summary>
 448        public void Dispose()
 0449        {
 0450            _disposed = true;
 0451            _context.Dispose();
 0452        }
 453
 454        private void EnsureNotDisposed()
 0455        {
 0456            ObjectDisposedException.ThrowIf(_disposed, nameof(ZstandardEncoder));
 0457        }
 458
 459        internal static void SetQuality(SafeZstdCompressHandle handle, int quality)
 0460        {
 0461            if (quality != 0)
 0462            {
 0463                ArgumentOutOfRangeException.ThrowIfLessThan(quality, ZstandardUtils.Quality_Min, nameof(quality));
 0464                ArgumentOutOfRangeException.ThrowIfGreaterThan(quality, ZstandardUtils.Quality_Max, nameof(quality));
 0465            }
 466
 0467            SetParameter(handle, Interop.Zstd.ZstdCParameter.ZSTD_c_compressionLevel, quality);
 0468        }
 469
 470        internal static void SetWindowLog(SafeZstdCompressHandle handle, int windowLog2)
 0471        {
 0472            if (windowLog2 != 0)
 0473            {
 0474                ArgumentOutOfRangeException.ThrowIfLessThan(windowLog2, ZstandardUtils.WindowLog_Min, nameof(windowLog2)
 0475                ArgumentOutOfRangeException.ThrowIfGreaterThan(windowLog2, ZstandardUtils.WindowLog_Max, nameof(windowLo
 0476            }
 477
 0478            SetParameter(handle, Interop.Zstd.ZstdCParameter.ZSTD_c_windowLog, windowLog2);
 0479        }
 480
 481        internal void SetDictionary(ZstandardDictionary dictionary)
 0482        {
 0483            Debug.Assert(_context != null);
 0484            ArgumentNullException.ThrowIfNull(dictionary);
 485
 0486            _context.SetDictionary(dictionary.CompressionDictionary);
 0487        }
 488
 489        internal static void SetParameter(SafeZstdCompressHandle handle, Interop.Zstd.ZstdCParameter parameter, int valu
 0490        {
 0491            Debug.Assert(handle != null);
 492
 0493            nuint result = Interop.Zstd.ZSTD_CCtx_setParameter(handle, parameter, value);
 0494            ZstandardUtils.ThrowIfError(result);
 0495        }
 496    }
 497}

Methods/Properties

.ctor()
.ctor(System.Int32)
.ctor(System.IO.Compression.ZstandardDictionary)
.ctor(System.Int32,System.Int32)
.ctor(System.IO.Compression.ZstandardDictionary,System.Int32)
.ctor(System.IO.Compression.ZstandardCompressionOptions)
InitializeEncoder()
Compress(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&,System.Int32&,System.Boolean)
Flush(System.Span`1<System.Byte>,System.Int32&)
CompressCore(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&,System.Int32&,Interop/Zstd/ZstdEndDirective)
GetMaxCompressedLength(System.Int64)
TryCompress(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&)
TryCompress(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&,System.Int32,System.Int32)
TryCompress(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&,System.IO.Compression.ZstandardDictionary,System.Int32)
TryCompressCore(System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int32&,System.Int32,System.Int32,System.IO.Compression.ZstandardDictionary)
Reset()
SetPrefix(System.ReadOnlyMemory`1<System.Byte>)
SetSourceLength(System.Int64)
Dispose()
EnsureNotDisposed()
SetQuality(Microsoft.Win32.SafeHandles.SafeZstdCompressHandle,System.Int32)
SetWindowLog(Microsoft.Win32.SafeHandles.SafeZstdCompressHandle,System.Int32)
SetDictionary(System.IO.Compression.ZstandardDictionary)
SetParameter(Microsoft.Win32.SafeHandles.SafeZstdCompressHandle,Interop/Zstd/ZstdCParameter,System.Int32)