ComManagedStream
sealed class ComManagedStream : Interface, Interface, IManagedWrapper<IStream, ISequentialStream>, IManagedWrapper
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
namespace Windows.Win32.System.Com
{
internal sealed class ComManagedStream : IStream.Interface, ISequentialStream.Interface, IManagedWrapper<IStream, ISequentialStream>, IManagedWrapper
{
[Nullable(1)]
private readonly Stream _dataStream;
private long _virtualPosition = -1;
[NullableContext(1)]
internal ComManagedStream(Stream stream, bool makeSeekable = false)
{
if (makeSeekable && !stream.CanSeek) {
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
_dataStream = memoryStream;
} else
_dataStream = stream;
}
private void ActualizeVirtualPosition()
{
if (_virtualPosition != -1) {
if (_virtualPosition > _dataStream.Length)
_dataStream.SetLength(_virtualPosition);
_dataStream.Position = _virtualPosition;
_virtualPosition = -1;
}
}
[NullableContext(1)]
public Stream GetDataStream()
{
return _dataStream;
}
unsafe HRESULT IStream.Interface.Clone(IStream** ppstm)
{
if (ppstm == null)
return HRESULT.E_POINTER;
*ppstm = ComHelpers.GetComPointer<IStream>(new ComManagedStream(_dataStream, false) {
_virtualPosition = _virtualPosition
});
return HRESULT.S_OK;
}
HRESULT IStream.Interface.Commit(uint grfCommitFlags)
{
_dataStream.Flush();
ActualizeVirtualPosition();
return HRESULT.S_OK;
}
unsafe HRESULT IStream.Interface.CopyTo(IStream* pstm, ulong cb, ulong* pcbRead, ulong* pcbWritten)
{
if (pstm != null) {
BufferScope<byte> bufferScope = new BufferScope<byte>(4096);
try {
ulong num = cb;
ulong num2 = 0;
ulong num3 = 0;
HRESULT result;
fixed (byte* pv = &bufferScope.GetPinnableReference()) {
while (num != 0) {
uint num4 = (uint)((num < (ulong)bufferScope.Length) ? ((int)num) : bufferScope.Length);
((IStream.Interface)this).Read((void*)pv, num4, &num4);
num -= num4;
num3 += num4;
if (num4 == 0)
break;
uint num5 = default(uint);
result = pstm->Write(pv, num4, &num5);
result.ThrowOnFailure((IntPtr)0);
num2 += num5;
}
}
if (pcbRead != null)
*pcbRead = num3;
if (pcbWritten != null)
*pcbWritten = num2;
result = HRESULT.S_OK;
return result;
} finally {
bufferScope.Dispose();
}
}
return HRESULT.STG_E_INVALIDPOINTER;
}
unsafe HRESULT ISequentialStream.Interface.Read(void* pv, uint cb, uint* pcbRead)
{
if (pv == null)
return HRESULT.STG_E_INVALIDPOINTER;
ActualizeVirtualPosition();
Span<byte> buffer = new Span<byte>(pv, checked((int)cb));
int num = _dataStream.Read(buffer);
if (pcbRead != null)
*pcbRead = (uint)num;
return HRESULT.S_OK;
}
unsafe HRESULT IStream.Interface.Read(void* pv, uint cb, uint* pcbRead)
{
return ((ISequentialStream.Interface)this).Read(pv, cb, pcbRead);
}
unsafe HRESULT IStream.Interface.Seek(long dlibMove, SeekOrigin dwOrigin, ulong* plibNewPosition)
{
long num = (_virtualPosition == -1) ? _dataStream.Position : _virtualPosition;
long length = _dataStream.Length;
switch (dwOrigin) {
case SeekOrigin.Begin:
if (dlibMove <= length) {
_dataStream.Position = dlibMove;
_virtualPosition = -1;
} else
_virtualPosition = dlibMove;
break;
case SeekOrigin.End:
if (dlibMove <= 0) {
_dataStream.Position = length + dlibMove;
_virtualPosition = -1;
} else
_virtualPosition = length + dlibMove;
break;
case SeekOrigin.Current:
if (dlibMove + num <= length) {
_dataStream.Position = num + dlibMove;
_virtualPosition = -1;
} else
_virtualPosition = dlibMove + num;
break;
}
if (plibNewPosition == null)
return HRESULT.S_OK;
*plibNewPosition = (ulong)((_virtualPosition == -1) ? _dataStream.Position : _virtualPosition);
return HRESULT.S_OK;
}
HRESULT IStream.Interface.SetSize(ulong libNewSize)
{
_dataStream.SetLength(checked((long)libNewSize));
return HRESULT.S_OK;
}
unsafe HRESULT IStream.Interface.Stat(STATSTG* pstatstg, uint grfStatFlag)
{
if (pstatstg == null)
return HRESULT.STG_E_INVALIDPOINTER;
*pstatstg = new STATSTG {
cbSize = _dataStream.Length,
type = 2,
grfMode = (_dataStream.CanWrite ? ((!_dataStream.CanRead) ? STGM.STGM_WRITE : STGM.STGM_READWRITE) : STGM.STGM_DIRECT)
};
if (grfStatFlag == 0) {
FileStream fileStream = _dataStream as FileStream;
pstatstg->pwcsName = (char*)(long)Marshal.StringToCoTaskMemUni((fileStream != null) ? fileStream.Name : _dataStream.ToString());
}
return HRESULT.S_OK;
}
HRESULT IStream.Interface.LockRegion(ulong libOffset, ulong cb, uint dwLockType)
{
return HRESULT.STG_E_INVALIDFUNCTION;
}
HRESULT IStream.Interface.Revert()
{
return HRESULT.S_OK;
}
HRESULT IStream.Interface.UnlockRegion(ulong libOffset, ulong cb, uint dwLockType)
{
return HRESULT.STG_E_INVALIDFUNCTION;
}
unsafe HRESULT ISequentialStream.Interface.Write(void* pv, uint cb, uint* pcbWritten)
{
if (pv == null)
return HRESULT.STG_E_INVALIDPOINTER;
ActualizeVirtualPosition();
ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(pv, checked((int)cb));
_dataStream.Write(buffer);
if (pcbWritten != null)
*pcbWritten = cb;
return HRESULT.S_OK;
}
unsafe HRESULT IStream.Interface.Write(void* pv, uint cb, uint* pcbWritten)
{
return ((ISequentialStream.Interface)this).Write(pv, cb, pcbWritten);
}
}
}