File: src\runtime\src\libraries\Common\src\Microsoft\Win32\SafeHandles\SafeZstdHandle.cs
Web Access
Project: System.IO.Compression.csproj (System.IO.Compression)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Buffers;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO.Compression;

namespace Microsoft.Win32.SafeHandles
{
    internal sealed class SafeZstdCompressHandle : SafeHandle
    {
        internal SafeZstdCDictHandle? _dictionary;
        internal MemoryHandle? _prefixHandle;
        public SafeZstdCompressHandle() : base(IntPtr.Zero, true) { }

        protected override bool ReleaseHandle()
        {
            Interop.Zstd.ZSTD_freeCCtx(handle);

            // release the addref we took in SetDictionary
            _dictionary?.DangerousRelease();

            if (_prefixHandle != null)
            {
                _prefixHandle.Value.Dispose();
                _prefixHandle = null;
            }
            return true;
        }

        public void SetDictionary(SafeZstdCDictHandle dictionary)
        {
            Debug.Assert(_dictionary == null);
            Debug.Assert(dictionary != null);

            bool added = false;
            try
            {
                dictionary.DangerousAddRef(ref added);
                ZstandardUtils.ThrowIfError(Interop.Zstd.ZSTD_CCtx_refCDict(this, dictionary));

                _dictionary = dictionary;
            }
            catch when (added)
            {
                dictionary.DangerousRelease();
                throw;
            }
        }

        public unsafe nuint SetPrefix(ReadOnlyMemory<byte> prefix)
        {
            MemoryHandle handle = prefix.Pin();

            nuint result = Interop.Zstd.ZSTD_CCtx_refPrefix(this, (byte*)handle.Pointer, (nuint)prefix.Length);

            if (Interop.Zstd.ZSTD_isError(result) != 0)
            {
                handle.Dispose();
            }
            else
            {
                _prefixHandle?.Dispose();
                _prefixHandle = handle;
            }

            return result;
        }

        public unsafe void Reset()
        {
            ZstandardUtils.ThrowIfError(Interop.Zstd.ZSTD_CCtx_reset(this, Interop.Zstd.ZstdResetDirective.ZSTD_reset_session_only));

            // prefix is not sticky and is cleared by reset
            if (_prefixHandle != null)
            {
                _prefixHandle.Value.Dispose();
                _prefixHandle = null;
            }
        }

        public override bool IsInvalid => handle == IntPtr.Zero;
    }

    internal sealed class SafeZstdDecompressHandle : SafeHandle
    {
        internal SafeZstdDDictHandle? _dictionary;
        internal MemoryHandle? _prefixHandle;
        public SafeZstdDecompressHandle() : base(IntPtr.Zero, true) { }

        protected override bool ReleaseHandle()
        {
            Interop.Zstd.ZSTD_freeDCtx(handle);

            // release the addref we took in SetDictionary
            _dictionary?.DangerousRelease();

            if (_prefixHandle != null)
            {
                _prefixHandle.Value.Dispose();
                _prefixHandle = null;
            }
            return true;
        }

        public void SetDictionary(SafeZstdDDictHandle dictionary)
        {
            Debug.Assert(_dictionary == null);
            Debug.Assert(dictionary != null);

            bool added = false;
            try
            {
                dictionary.DangerousAddRef(ref added);
                ZstandardUtils.ThrowIfError(Interop.Zstd.ZSTD_DCtx_refDDict(this, dictionary));

                _dictionary = dictionary;
            }
            catch when (added)
            {
                dictionary.DangerousRelease();
                throw;
            }
        }

        public unsafe nuint SetPrefix(ReadOnlyMemory<byte> prefix)
        {
            MemoryHandle handle = prefix.Pin();

            nuint result = Interop.Zstd.ZSTD_DCtx_refPrefix(this, (byte*)handle.Pointer, (nuint)prefix.Length);

            if (Interop.Zstd.ZSTD_isError(result) != 0)
            {
                handle.Dispose();
            }
            else
            {
                _prefixHandle?.Dispose();
                _prefixHandle = handle;
            }

            return result;
        }

        public unsafe void Reset()
        {
            ZstandardUtils.ThrowIfError(Interop.Zstd.ZSTD_DCtx_reset(this, Interop.Zstd.ZstdResetDirective.ZSTD_reset_session_only));

            // prefix is not sticky and is cleared by reset
            if (_prefixHandle != null)
            {
                _prefixHandle.Value.Dispose();
                _prefixHandle = null;
            }
        }

        public override bool IsInvalid => handle == IntPtr.Zero;
    }

    internal sealed class SafeZstdCDictHandle : SafeHandle
    {
        public SafeZstdCDictHandle() : base(IntPtr.Zero, true) { }

        internal PinnedGCHandle<byte[]> _pinnedData;

        protected override bool ReleaseHandle()
        {
            Interop.Zstd.ZSTD_freeCDict(handle);
            _pinnedData.Dispose();
            return true;
        }

        public override bool IsInvalid => handle == IntPtr.Zero;
    }

    internal sealed class SafeZstdDDictHandle : SafeHandle
    {
        public SafeZstdDDictHandle() : base(IntPtr.Zero, true) { }

        internal PinnedGCHandle<byte[]> _pinnedData;

        protected override bool ReleaseHandle()
        {
            Interop.Zstd.ZSTD_freeDDict(handle);
            _pinnedData.Dispose();
            return true;
        }

        public override bool IsInvalid => handle == IntPtr.Zero;
    }
}