File: MachO\FileUtils\StreamExtensions.cs
Web Access
Project: src\src\runtime\src\installer\managed\Microsoft.NET.HostModel\Microsoft.NET.HostModel.csproj (Microsoft.NET.HostModel)
// 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.Binary;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using Microsoft.NET.HostModel.MachO;

internal static class StreamExtensions
{
    public static uint ReadUInt32BigEndian(this Stream stream)
    {
#if NET
        Span<byte> buffer = stackalloc byte[sizeof(uint)];
#else
        byte[] buffer = new byte[sizeof(uint)];
#endif
        stream.ReadExactly(buffer);
        return BinaryPrimitives.ReadUInt32BigEndian(buffer);
    }

    public static uint ReadUInt32BigEndian(this MemoryMappedViewAccessor accessor, long offset)
    {
        return accessor.ReadUInt32(offset).ConvertFromBigEndian();
    }

    public static void WriteUInt32BigEndian(this Stream stream, uint value)
    {
#if NET
        Span<byte> buffer = stackalloc byte[sizeof(uint)];
#else
        byte[] buffer = new byte[sizeof(uint)];
#endif
        BinaryPrimitives.WriteUInt32BigEndian(buffer, value);
        stream.Write(buffer);
    }

    public static void WriteUInt32BigEndian(this MemoryMappedViewAccessor accessor, long offset, uint value)
    {
        accessor.Write(offset, value.ConvertToBigEndian());
    }

    public static unsafe void Read<T>(this Stream stream, out T result) where T : unmanaged
    {
#if NET
        Span<byte> buffer = sizeof(T) < 256 ? stackalloc byte[sizeof(T)] : new byte[sizeof(T)];
#else
        byte[] buffer = new byte[sizeof(T)];
#endif
        stream.ReadExactly(buffer);
        result = MemoryMarshal.Read<T>(buffer);
    }

    public static unsafe void Write<T>(this Stream stream, ref T value) where T : unmanaged
    {
        byte[] buffer = new byte[sizeof(T)];
#pragma warning disable CS9191 // The 'ref' modifier for an argument corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead.
        MemoryMarshal.Write(buffer, ref value);
#pragma warning restore CS9191
        stream.Write(buffer, 0, buffer.Length);
    }

#if !NET
    /// <summary>
    /// Reads exactly the specified number of bytes from the stream.
    /// </summary>
    /// <param name="stream">The stream to read from.</param>
    /// <param name="buffer">The buffer to read into.</param>
    /// <exception cref="EndOfStreamException">Thrown if the end of the stream is reached before reading the specified number of bytes.</exception>
    public static void ReadExactly(this Stream stream, byte[] buffer)
    {
        int totalBytesRead = 0;
        while (totalBytesRead < buffer.Length)
        {
            int bytesRead = stream.Read(buffer, totalBytesRead, buffer.Length - totalBytesRead);
            if (bytesRead == 0)
            {
                throw new EndOfStreamException("Reached end of stream before reading expected number of bytes.");
            }
            totalBytesRead += bytesRead;
        }
    }

    public static int Write(this Stream stream, byte[] buffer)
    {
        stream.Write(buffer, 0, buffer.Length);
        return buffer.Length;
    }
#endif
}