File: Utilities\UnsafeComStreamWrapper.cs
Web Access
Project: src\src\symreader\src\Microsoft.DiaSymReader\Microsoft.DiaSymReader.csproj (Microsoft.DiaSymReader)
// Licensed to the.NET Foundation under one or more agreements.
// The.NET Foundation licenses this file to you under the MIT license.
// See the License.txt file in the project root for more information.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.ComTypes;

#if NET9_0_OR_GREATER
using System.Runtime.InteropServices.Marshalling;
#endif

namespace Microsoft.DiaSymReader.Utilities;

/// <summary>
/// Provides an <see cref="IStream"/>-like wrapper around an <see cref="IUnsafeComStream"/> to handle incompatibilities
/// introduced with source-generated ComWrappers.
/// </summary>
/// <remarks>
/// <see cref="ComStreamWrapper"/> is a wrapper around a <see cref="Stream"/> that implements both interface definitions.
/// This is a wrapper around a marshalled <see cref="IUnsafeComStream"/> that also implements the <see cref="IStream"/> interface./>
/// </remarks>
#if NET9_0_OR_GREATER
[GeneratedComClass]
#endif
internal partial class UnsafeComStreamWrapper : IUnsafeComStream, IStream
{
    private readonly IUnsafeComStream _stream;

    public UnsafeComStreamWrapper(IUnsafeComStream stream)
    {
        _stream = stream;
    }

    #region IUnsafeComStream

    public unsafe void Read(byte* pv, int cb, int* pcbRead) => _stream.Read(pv, cb, pcbRead);

    public unsafe void Write(byte* pv, int cb, int* pcbWritten) => _stream.Write(pv, cb, pcbWritten);

    public unsafe void Seek(long dlibMove, int dwOrigin, long* plibNewPosition) => _stream.Seek(dlibMove, dwOrigin, plibNewPosition);

    public void SetSize(long libNewSize) => _stream.SetSize(libNewSize);

    public unsafe void CopyTo(IntPtr pstm, long cb, int* pcbRead, int* pcbWritten) => _stream.CopyTo(pstm, cb, pcbRead, pcbWritten);

    public void Commit(int grfCommitFlags) => _stream.Commit(grfCommitFlags);

    public void Revert() => _stream.Revert();

    public void LockRegion(long libOffset, long cb, int dwLockType) => _stream.LockRegion(libOffset, cb, dwLockType);

    public void UnlockRegion(long libOffset, long cb, int dwLockType) => _stream.UnlockRegion(libOffset, cb, dwLockType);

    public void Stat(out STATSTG pstatstg, int grfStatFlag) => _stream.Stat(out pstatstg, grfStatFlag);

    public void Clone(out IntPtr ppstm) => _stream.Clone(out ppstm);

    #endregion

    #region IStream

    public void Clone(out IStream ppstm) => throw new NotSupportedException("Clone is not supported in this version.");

    public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) => throw new NotImplementedException("CopyTo is not implemented in this version.");

    public unsafe void Read(byte[] pv, int cb, IntPtr pcbRead)
    {
        fixed (byte* pByte = pv)
        {
            _stream.Read(pByte, cb, (int*)pcbRead);
        }
    }

    public unsafe void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) => _stream.Seek(dlibMove, dwOrigin, (long*)plibNewPosition);

    public unsafe void Write(byte[] pv, int cb, IntPtr pcbWritten)
    {
        fixed (byte* pByte = pv)
        {
            _stream.Write(pByte, cb, (int*)pcbWritten);
        }
    }

    void System.Runtime.InteropServices.ComTypes.IStream.Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
    {
        _stream.Stat(out var unsafeSTASTG, grfStatFlag);

        pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG()
        {
            cbSize = unsafeSTASTG.cbSize,
        };
    }

    #endregion
}