|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.IO
{
/// <summary>
/// Pins a <see langword="byte[]"/>, exposing it as an unmanaged memory stream. Used in <see cref="System.Resources.ResourceReader"/> for corner cases.
/// </summary>
internal sealed unsafe class PinnedBufferMemoryStream : UnmanagedMemoryStream
{
private readonly byte[] _array;
private GCHandle _pinningHandle;
internal PinnedBufferMemoryStream(byte[] array)
{
Debug.Assert(array != null, "Array can't be null");
_array = array;
_pinningHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
// Now the byte[] is pinned for the lifetime of this instance.
// But I also need to get a pointer to that block of memory...
int len = array.Length;
fixed (byte* ptr = &MemoryMarshal.GetReference((Span<byte>)array))
Initialize(ptr, len, len, FileAccess.Read);
}
#if !RESOURCES_EXTENSIONS
public override int Read(Span<byte> buffer) => ReadCore(buffer);
public override void Write(ReadOnlySpan<byte> buffer) => WriteCore(buffer);
#endif
~PinnedBufferMemoryStream()
{
Dispose(false);
}
protected override void Dispose(bool disposing)
{
if (_pinningHandle.IsAllocated)
{
_pinningHandle.Free();
}
base.Dispose(disposing);
}
}
}
|