File: System\Reflection\Internal\MemoryBlocks\MemoryBlockProvider.cs
Web Access
Project: src\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata)
// 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.CodeAnalysis;
using System.IO;
using System.Reflection.PortableExecutable;
 
namespace System.Reflection.Internal
{
    internal abstract class MemoryBlockProvider : IDisposable
    {
        /// <summary>
        /// Creates and hydrates a memory block representing all data.
        /// </summary>
        /// <exception cref="IOException">Error while reading from the memory source.</exception>
        public AbstractMemoryBlock GetMemoryBlock()
        {
            return GetMemoryBlockImpl(0, Size);
        }
 
        /// <summary>
        /// Creates and hydrates a memory block representing data in the specified range.
        /// </summary>
        /// <param name="start">Starting offset relative to the beginning of the data represented by this provider.</param>
        /// <param name="size">Size of the resulting block.</param>
        /// <exception cref="IOException">Error while reading from the memory source.</exception>
        public AbstractMemoryBlock GetMemoryBlock(int start, int size)
        {
            // Add cannot overflow as it is the sum of two 32-bit values done in 64 bits.
            // Negative start or size is handle by overflow to greater than maximum size = int.MaxValue.
            if ((ulong)(unchecked((uint)start)) + unchecked((uint)size) > (ulong)this.Size)
            {
                Throw.ImageTooSmallOrContainsInvalidOffsetOrCount();
            }
 
            return GetMemoryBlockImpl(start, size);
        }
 
        /// <exception cref="IOException">IO error while reading from the underlying stream.</exception>
        protected abstract AbstractMemoryBlock GetMemoryBlockImpl(int start, int size);
 
        /// <summary>
        /// Gets the <see cref="Stream"/> backing the <see cref="MemoryBlockProvider"/>, if there is one.
        /// </summary>
        /// <remarks>
        /// It is the caller's responsibility to use <paramref name="stream"/> only
        /// while locking on <paramref name="streamGuard"/>, and not read outside the
        /// bounds defined by <paramref name="imageStart"/> and <paramref name="imageSize"/>.
        /// </remarks>
        public virtual bool TryGetUnderlyingStream([NotNullWhen(true)] out Stream? stream, out long imageStart, out int imageSize, [NotNullWhen(true)] out object? streamGuard)
        {
            stream = null;
            imageStart = 0;
            imageSize = 0;
            streamGuard = null;
            return false;
        }
 
        /// <summary>
        /// The size of the data.
        /// </summary>
        public abstract int Size { get; }
 
        protected abstract void Dispose(bool disposing);
 
        public void Dispose()
        {
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
    }
}