|
//------------------------------------------------------------------------------
// Microsoft Avalon
// Copyright (c) Microsoft Corporation, 2002-2003
//
// File: StreamAsIStream.cs
//------------------------------------------------------------------------------
#pragma warning disable 1634, 1691 // Allow suppression of certain presharp messages
using System.Windows.Media;
using System.Security;
using System.Security.Permissions;
using System;
using MS.Internal;
using MS.Win32;
using System.Reflection;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using MS.Internal.PresentationCore;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods;
// TODOTODO Make our own namespace for internal stuff.
namespace System.Windows.Media
{
#region StreamDescriptor
[StructLayout(LayoutKind.Sequential)]
internal struct StreamDescriptor
{
internal delegate void Dispose(ref StreamDescriptor pSD);
internal delegate int Read(ref StreamDescriptor pSD, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out]byte[] buffer, uint cb, out uint cbRead);
/// <SecurityNote>
/// Critical - Recieves native pointers as parameters.
/// </SecurityNote>
[SecurityCritical]
internal unsafe delegate int Seek(ref StreamDescriptor pSD, long offset, uint origin, long* plibNewPostion);
internal delegate int Stat(ref StreamDescriptor pSD, out System.Runtime.InteropServices.ComTypes.STATSTG statstg, uint grfStatFlag);
internal delegate int Write(ref StreamDescriptor pSD, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]byte[] buffer, uint cb, out uint cbWritten);
/// <SecurityNote>
/// Critical - Recieves native pointers as parameters.
/// </SecurityNote>
[SecurityCritical]
internal delegate int CopyTo(ref StreamDescriptor pSD, IntPtr pstm, long cb, out long cbRead, out long cbWritten);
internal delegate int SetSize(ref StreamDescriptor pSD, long value);
internal delegate int Revert(ref StreamDescriptor pSD);
internal delegate int Commit(ref StreamDescriptor pSD, UInt32 grfCommitFlags);
internal delegate int LockRegion(ref StreamDescriptor pSD, long libOffset, long cb, uint dwLockType);
internal delegate int UnlockRegion(ref StreamDescriptor pSD, long libOffset, long cb, uint dwLockType);
internal delegate int Clone(ref StreamDescriptor pSD, out IntPtr stream);
internal delegate int CanWrite(ref StreamDescriptor pSD, out bool canWrite);
internal delegate int CanSeek(ref StreamDescriptor pSD, out bool canSeek);
internal Dispose pfnDispose;
internal Read pfnRead;
/// <SecurityNote>
/// Critical - Field for Critical delegate.
/// </SecurityNote>
[SecurityCritical]
internal Seek pfnSeek;
internal Stat pfnStat;
internal Write pfnWrite;
/// <SecurityNote>
/// Critical - Field for Critical delegate.
/// </SecurityNote>
[SecurityCritical]
internal CopyTo pfnCopyTo;
internal SetSize pfnSetSize;
internal Commit pfnCommit;
internal Revert pfnRevert;
internal LockRegion pfnLockRegion;
internal UnlockRegion pfnUnlockRegion;
internal Clone pfnClone;
internal CanWrite pfnCanWrite;
internal CanSeek pfnCanSeek;
///<SecurityNote>
/// Critical: This code calls into link demand protected GCHandle
/// TreatAsSafe: This code is ok to expose especially since it does not expose the handle
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
internal static void StaticDispose(ref StreamDescriptor pSD)
{
Debug.Assert(((IntPtr)pSD.m_handle) != IntPtr.Zero, "If this asserts fires: why is it firing. It might be legal in future.");
StreamAsIStream sais = (StreamAsIStream)(pSD.m_handle.Target);
((System.Runtime.InteropServices.GCHandle)(pSD.m_handle)).Free();
}
internal System.Runtime.InteropServices.GCHandle m_handle;
}
#endregion
#region StaticPtrs
/// <summary>
/// We need to keep the delegates alive.
/// </summary>
internal static class StaticPtrs
{
///<SecurityNote>
/// Critical - this method has an unsafe block and references StreamAsIStream.Seek
/// TreatAsSafe - referenced function pointer is well known
///</SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
static StaticPtrs()
{
StaticPtrs.pfnDispose = new StreamDescriptor.Dispose(StreamDescriptor.StaticDispose);
StaticPtrs.pfnClone = new StreamDescriptor.Clone(StreamAsIStream.Clone);
StaticPtrs.pfnCommit = new StreamDescriptor.Commit(StreamAsIStream.Commit);
StaticPtrs.pfnCopyTo = new StreamDescriptor.CopyTo(StreamAsIStream.CopyTo);
StaticPtrs.pfnLockRegion = new StreamDescriptor.LockRegion(StreamAsIStream.LockRegion);
StaticPtrs.pfnRead = new StreamDescriptor.Read(StreamAsIStream.Read);
StaticPtrs.pfnRevert = new StreamDescriptor.Revert(StreamAsIStream.Revert);
unsafe
{
StaticPtrs.pfnSeek = new StreamDescriptor.Seek(StreamAsIStream.Seek);
}
StaticPtrs.pfnSetSize = new StreamDescriptor.SetSize(StreamAsIStream.SetSize);
StaticPtrs.pfnStat = new StreamDescriptor.Stat(StreamAsIStream.Stat);
StaticPtrs.pfnUnlockRegion = new StreamDescriptor.UnlockRegion(StreamAsIStream.UnlockRegion);
StaticPtrs.pfnWrite = new StreamDescriptor.Write(StreamAsIStream.Write);
StaticPtrs.pfnCanWrite = new StreamDescriptor.CanWrite(StreamAsIStream.CanWrite);
StaticPtrs.pfnCanSeek = new StreamDescriptor.CanSeek(StreamAsIStream.CanSeek);
}
internal static StreamDescriptor.Dispose pfnDispose;
internal static StreamDescriptor.Read pfnRead;
/// <SecurityNote>
/// Critical - Field for Critical delegate.
/// </SecurityNote>
[SecurityCritical]
internal static StreamDescriptor.Seek pfnSeek;
internal static StreamDescriptor.Stat pfnStat;
internal static StreamDescriptor.Write pfnWrite;
/// <SecurityNote>
/// Critical - Field for Critical delegate.
/// </SecurityNote>
[SecurityCritical]
internal static StreamDescriptor.CopyTo pfnCopyTo;
internal static StreamDescriptor.SetSize pfnSetSize;
internal static StreamDescriptor.Commit pfnCommit;
internal static StreamDescriptor.Revert pfnRevert;
internal static StreamDescriptor.LockRegion pfnLockRegion;
internal static StreamDescriptor.UnlockRegion pfnUnlockRegion;
internal static StreamDescriptor.Clone pfnClone;
internal static StreamDescriptor.CanWrite pfnCanWrite;
internal static StreamDescriptor.CanSeek pfnCanSeek;
}
#endregion
#region StreamAsIStream
//CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity]
internal class StreamAsIStream
{
#region Instance Data
const int STREAM_SEEK_SET = 0x0;
const int STREAM_SEEK_CUR = 0x1;
const int STREAM_SEEK_END = 0x2;
protected System.IO.Stream dataStream;
private Exception _lastException;
// to support seeking ahead of the stream length...
private long virtualPosition = -1;
#endregion
#region Constructor
private StreamAsIStream(System.IO.Stream dataStream)
{
this.dataStream = dataStream;
}
#endregion
#region Private Methods
private void ActualizeVirtualPosition()
{
if (virtualPosition == -1)
{
return;
}
if (virtualPosition > dataStream.Length)
{
dataStream.SetLength(virtualPosition);
}
dataStream.Position = virtualPosition;
virtualPosition = -1;
}
#endregion
#region StreamFunctions
public int Clone(out IntPtr stream)
{
stream = IntPtr.Zero;
#pragma warning disable 6500
try
{
Verify();
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.E_NOTIMPL;
}
public int Commit(uint grfCommitFlags)
{
#pragma warning disable 6500
try
{
Verify();
dataStream.Flush();
// Extend the length of the file if needed.
ActualizeVirtualPosition();
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
/// <SecurityNote>
/// Critical - Recieves native pointers as parameters and calls P/Invoke method MILIStreamWrite.
/// </SecurityNote>
[SecurityCritical]
public int CopyTo(IntPtr /* IStream */ pstm, long cb, out long cbRead, out long cbWritten)
{
int hr = NativeMethods.S_OK;
uint bufsize = 4096; // one page
byte[] buffer = new byte[bufsize];
cbWritten = 0;
cbRead = 0;
#pragma warning disable 6500
try
{
Verify();
while (cbWritten < cb)
{
uint toRead = bufsize;
if (cbWritten + toRead > cb)
{
toRead = (uint) (cb - cbWritten);
}
uint read = 0;
hr = Read(buffer, toRead, out read);
if (read == 0)
{
break;
}
cbRead += read;
uint written = 0;
hr = MILIStreamWrite(pstm, buffer, read, out written);
if (written != read)
{
return hr;
}
cbWritten += read;
}
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return hr;
}
public int LockRegion(long libOffset, long cb, uint dwLockType)
{
#pragma warning disable 6500
try
{
Verify();
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.E_NOTIMPL;
}
public int Read(byte[] buffer, uint cb, out uint cbRead)
{
cbRead = 0;
#pragma warning disable 6500
try
{
Verify();
ActualizeVirtualPosition();
cbRead = (uint) dataStream.Read(buffer, 0, (int) cb);
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int Revert()
{
#pragma warning disable 6500
try
{
Verify();
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.E_NOTIMPL;
}
///<SecurityNote>
/// Critical - this method is unsafe - it cannot warrant the validity of the given pointer
///</SecurityNote>
[SecurityCritical]
public unsafe int Seek(long offset, uint origin, long * plibNewPostion)
{
#pragma warning disable 6500
try
{
Verify();
long pos = virtualPosition;
if (virtualPosition == -1)
{
pos = dataStream.Position;
}
long len = dataStream.Length;
switch (origin)
{
case STREAM_SEEK_SET:
if (offset <= len)
{
dataStream.Position = offset;
virtualPosition = -1;
}
else
{
virtualPosition = offset;
}
break;
case STREAM_SEEK_END:
if (offset <= 0)
{
dataStream.Position = len + offset;
virtualPosition = -1;
}
else
{
virtualPosition = len + offset;
}
break;
case STREAM_SEEK_CUR:
if (offset+pos <= len)
{
dataStream.Position = pos + offset;
virtualPosition = -1;
}
else
{
virtualPosition = offset + pos;
}
break;
}
if (plibNewPostion!=null)
{
if (virtualPosition != -1)
{
*plibNewPostion = virtualPosition;
}
else
{
*plibNewPostion = dataStream.Position;
}
}
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int SetSize(long value)
{
#pragma warning disable 6500
try
{
Verify();
dataStream.SetLength(value);
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int Stat(out System.Runtime.InteropServices.ComTypes.STATSTG statstg, uint grfStatFlag)
{
System.Runtime.InteropServices.ComTypes.STATSTG statstgOut = new System.Runtime.InteropServices.ComTypes.STATSTG();
statstg = statstgOut;
#pragma warning disable 6500
try
{
Verify();
statstgOut.type = 2; // STGTY_STREAM
statstgOut.cbSize = dataStream.Length;
statstgOut.grfLocksSupported = 2; //LOCK_EXCLUSIVE
statstgOut.pwcsName = null;
statstg = statstgOut;
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int UnlockRegion(long libOffset, long cb, uint dwLockType)
{
#pragma warning disable 6500
try
{
Verify();
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.E_NOTIMPL;
}
public int Write(byte[] buffer, uint cb, out uint cbWritten)
{
cbWritten = 0;
#pragma warning disable 6500
try
{
Verify();
ActualizeVirtualPosition();
dataStream.Write(buffer, 0, (int) cb);
cbWritten = cb;
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int CanWrite(out bool canWrite)
{
canWrite = false;
#pragma warning disable 6500
try
{
Verify();
canWrite = dataStream.CanWrite;
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
public int CanSeek(out bool canSeek)
{
canSeek = false;
#pragma warning disable 6500
try
{
Verify();
canSeek = dataStream.CanSeek;
}
catch (Exception e)
{
// store the last exception
_lastException = e;
return SecurityHelper.GetHRForException(e);
}
#pragma warning restore 6500
return NativeMethods.S_OK;
}
#endregion
#region Verify
private void Verify()
{
if (this.dataStream == null)
{
throw new System.ObjectDisposedException(SR.Get(SRID.Media_StreamClosed));
}
}
#endregion
#region Delegate Implemetations
///<SecurityNote>
/// Critical: This code calls into link demand protected GCHandle
/// TreatAsSafe: This code is ok to expose
/// </SecurityNote>
[SecurityCritical,SecurityTreatAsSafe]
internal static StreamAsIStream FromSD(ref StreamDescriptor sd)
{
Debug.Assert(((IntPtr)sd.m_handle) != IntPtr.Zero, "Stream is disposed.");
System.Runtime.InteropServices.GCHandle handle = (System.Runtime.InteropServices.GCHandle)(sd.m_handle);
return (StreamAsIStream)(handle.Target);
}
internal static int Clone(ref StreamDescriptor pSD, out IntPtr stream)
{
return (StreamAsIStream.FromSD(ref pSD)).Clone(out stream);
}
internal static int Commit(ref StreamDescriptor pSD, UInt32 grfCommitFlags)
{
return (StreamAsIStream.FromSD(ref pSD)).Commit(grfCommitFlags);
}
/// <SecurityNote>
/// Critical - Recieves native pointers as parameters.
/// </SecurityNote>
[SecurityCritical]
internal static int CopyTo(ref StreamDescriptor pSD, IntPtr pstm, long cb, out long cbRead, out long cbWritten)
{
return (StreamAsIStream.FromSD(ref pSD)).CopyTo(pstm, cb, out cbRead, out cbWritten);
}
internal static int LockRegion(ref StreamDescriptor pSD, long libOffset, long cb, uint dwLockType)
{
return (StreamAsIStream.FromSD(ref pSD)).LockRegion(libOffset, cb, dwLockType);
}
internal static int Read(ref StreamDescriptor pSD, byte[] buffer, uint cb, out uint cbRead)
{
return (StreamAsIStream.FromSD(ref pSD)).Read(buffer, cb, out cbRead);
}
internal static int Revert(ref StreamDescriptor pSD)
{
return (StreamAsIStream.FromSD(ref pSD)).Revert();
}
///<SecurityNote>
/// Critical - this method is unsafe - it cannot warrant the validity of the given pointer
///</SecurityNote>
[SecurityCritical]
internal unsafe static int Seek(ref StreamDescriptor pSD, long offset, uint origin, long* plibNewPostion)
{
return (StreamAsIStream.FromSD(ref pSD)).Seek(offset, origin, plibNewPostion);
}
internal static int SetSize(ref StreamDescriptor pSD, long value)
{
return (StreamAsIStream.FromSD(ref pSD)).SetSize(value);
}
internal static int Stat(ref StreamDescriptor pSD, out System.Runtime.InteropServices.ComTypes.STATSTG statstg, uint grfStatFlag)
{
return (StreamAsIStream.FromSD(ref pSD)).Stat(out statstg, grfStatFlag);
}
internal static int UnlockRegion(ref StreamDescriptor pSD, long libOffset, long cb, uint dwLockType)
{
return (StreamAsIStream.FromSD(ref pSD)).UnlockRegion(libOffset, cb, dwLockType);
}
internal static int Write(ref StreamDescriptor pSD, byte[] buffer, uint cb, out uint cbWritten)
{
return (StreamAsIStream.FromSD(ref pSD)).Write(buffer, cb, out cbWritten);
}
internal static int CanWrite(ref StreamDescriptor pSD, out bool canWrite)
{
return (StreamAsIStream.FromSD(ref pSD)).CanWrite(out canWrite);
}
internal static int CanSeek(ref StreamDescriptor pSD, out bool canSeek)
{
return (StreamAsIStream.FromSD(ref pSD)).CanSeek(out canSeek);
}
#endregion
// Takes an IStream that is potentially not seekable and returns
// a seekable memory stream that is a copy of it.
/// <SecurityNote>
/// Critical - calls unmanaged code, takes unmanaged pointer argument
/// </SecurityNote>
[SecurityCritical]
internal static IntPtr IStreamMemoryFrom(IntPtr comStream)
{
IntPtr pIStream = IntPtr.Zero;
using (FactoryMaker myFactory = new FactoryMaker())
{
if (HRESULT.Failed(UnsafeNativeMethods.WICImagingFactory.CreateStream(myFactory.ImagingFactoryPtr, out pIStream)))
{
return IntPtr.Zero;
}
if (HRESULT.Failed(UnsafeNativeMethods.WICStream.InitializeFromIStream(pIStream, comStream)))
{
UnsafeNativeMethods.MILUnknown.ReleaseInterface(ref pIStream);
return IntPtr.Zero;
}
}
return pIStream;
}
/// <SecurityNote>
/// Critical - calls unmanaged code, accepts unmanaged pointers
/// </SecurityNote>
[SecurityCritical]
internal static IntPtr IStreamFrom(IntPtr memoryBuffer, int bufferSize)
{
IntPtr pIStream = IntPtr.Zero;
using (FactoryMaker myFactory = new FactoryMaker())
{
if (HRESULT.Failed(UnsafeNativeMethods.WICImagingFactory.CreateStream(myFactory.ImagingFactoryPtr, out pIStream)))
{
return IntPtr.Zero;
}
if (HRESULT.Failed(UnsafeNativeMethods.WICStream.InitializeFromMemory(pIStream, memoryBuffer, (uint) bufferSize)))
{
UnsafeNativeMethods.MILUnknown.ReleaseInterface(ref pIStream);
return IntPtr.Zero;
}
}
return pIStream;
}
#region IStreamFrom System.IO.Stream
/// <SecurityNote>
/// Critical - calls critical code, create unmanaged structures
/// </SecurityNote>
[SecurityCritical]
internal static IntPtr IStreamFrom(System.IO.Stream stream)
{
if (stream == null)
{
throw new System.ArgumentNullException("stream");
}
IntPtr pStream = IntPtr.Zero;
StreamAsIStream sais = new StreamAsIStream(stream);
StreamDescriptor sd = new StreamDescriptor();
sd.pfnDispose = StaticPtrs.pfnDispose;
sd.pfnClone = StaticPtrs.pfnClone;
sd.pfnCommit = StaticPtrs.pfnCommit;
sd.pfnCopyTo = StaticPtrs.pfnCopyTo;
sd.pfnLockRegion = StaticPtrs.pfnLockRegion;
sd.pfnRead = StaticPtrs.pfnRead;
sd.pfnRevert = StaticPtrs.pfnRevert;
unsafe
{
sd.pfnSeek = StaticPtrs.pfnSeek;
}
sd.pfnSetSize = StaticPtrs.pfnSetSize;
sd.pfnStat = StaticPtrs.pfnStat;
sd.pfnUnlockRegion = StaticPtrs.pfnUnlockRegion;
sd.pfnWrite = StaticPtrs.pfnWrite;
sd.pfnCanWrite = StaticPtrs.pfnCanWrite;
sd.pfnCanSeek = StaticPtrs.pfnCanSeek;
sd.m_handle = System.Runtime.InteropServices.GCHandle.Alloc(sais, System.Runtime.InteropServices.GCHandleType.Normal);
HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MILCreateStreamFromStreamDescriptor(ref sd, out pStream));
return pStream;
}
#endregion
//CASRemoval:[System.Security.SuppressUnmanagedCodeSecurity, DllImport("DllImport.MilCore")]
[DllImport(DllImport.MilCore)]//CASRemoval:
private extern static int /* HRESULT */ MILIStreamWrite(IntPtr pStream, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]byte[] buffer, uint cb, out uint cbWritten);
}
#endregion
}
|