-//------------------------------------------------------------------------------
//
// System.IO.UnmanagedMemoryStream.cs
//
// Copyright (C) 2006 Sridhar Kulkarni, All Rights Reserved
//
-// Author: Sridhar Kulkarni (sridharkulkarni@gmail.com)
-// Created: Monday, July 10, 2006
+// Authors:
+// Sridhar Kulkarni (sridharkulkarni@gmail.com)
+// Gert Driesen (drieseng@users.sourceforge.net)
+// Sebastien Pouliot <sebastien@ximian.com>
//
-//------------------------------------------------------------------------------
-
-//
-// Copyright (C) 2005-2006 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2006, 2009 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_2_0
-
using System;
using System.IO;
using System.Runtime.InteropServices;
-
namespace System.IO
{
- [CLSCompliantAttribute(false)]
public class UnmanagedMemoryStream : Stream
{
long length;
bool closed;
- bool canseek = false;
long capacity;
FileAccess fileaccess;
IntPtr initial_pointer;
- IntPtr pointer_position;
long initial_position;
long current_position;
+#if NET_4_0
+ SafeBuffer safebuffer;
+#endif
+
+ internal event EventHandler Closed;
#region Constructor
protected UnmanagedMemoryStream()
{
- fileaccess = FileAccess.Read;
- initial_position = 0;
- canseek = true;
- closed = false;
- current_position = initial_position;
+ closed = true;
}
-
- public unsafe UnmanagedMemoryStream (byte *pointer, long len)
+
+ [CLSCompliantAttribute(false)]
+ public unsafe UnmanagedMemoryStream (byte *pointer, long length) :
+ this (pointer, length, length, FileAccess.Read)
{
- if (pointer == null)
- throw new ArgumentNullException("The pointer value is a null reference ");
- if (len < 0)
- throw new ArgumentOutOfRangeException("The length value is less than zero");
- fileaccess = FileAccess.Read;
- length = len;
- capacity = len;
- initial_position = 0;
- current_position = initial_position;
- canseek = true;
- closed = false;
- initial_pointer = new IntPtr((void*)pointer);
}
- public unsafe UnmanagedMemoryStream (byte *pointer, long len, long cap, FileAccess access)
+ [CLSCompliantAttribute(false)]
+ public unsafe UnmanagedMemoryStream (byte *pointer, long length, long capacity, FileAccess access)
{
- if (pointer == null)
- throw new ArgumentNullException("The pointer value is a null reference");
- if (len < 0)
- throw new ArgumentOutOfRangeException("The length value is less than zero");
- if (capacity < 0)
- throw new ArgumentOutOfRangeException("The capacity value is less than zero");
- if (len > capacity)
- throw new ArgumentOutOfRangeException("The length value is greater than the capacity value");
- fileaccess = access;
- length = len;
- capacity = cap;
- initial_position = 0;
- current_position = initial_position;
- canseek = true;
- initial_pointer = new IntPtr ((void*)pointer);
- closed = false;
- fileaccess = access;
+ closed = true;
+ Initialize (pointer, length, capacity, access);
}
+
+#if NET_4_0
+ public UnmanagedMemoryStream (SafeBuffer buffer, long offset, long length) :
+ this (buffer, offset, length, FileAccess.Read)
+ {
+ }
+
+ public UnmanagedMemoryStream (SafeBuffer buffer, long offset, long length, FileAccess access)
+ {
+ closed = true;
+ Initialize (buffer, offset, length, access);
+ }
+#endif
#endregion
#region Properties
public override bool CanRead {
get {
- if (closed)
- return false;
- else
- return ((fileaccess == FileAccess.Read || fileaccess == FileAccess.ReadWrite)? true:false);
+ return (!closed && (fileaccess != FileAccess.Write));
}
}
public override bool CanSeek {
get {
- return ((closed) ? false : true);
+ return !closed;
}
}
public override bool CanWrite {
get {
- if (closed)
- return (false);
- else
- return ((fileaccess == FileAccess.Write || fileaccess == FileAccess.ReadWrite)? true:false);
+ return (!closed && (fileaccess != FileAccess.Read));
}
}
public long Capacity {
return (length);
}
}
+
public override long Position {
get {
if (closed)
throw new ObjectDisposedException("The stream is closed");
- else
- return (current_position);
+ return (current_position);
}
set {
if (closed)
throw new ObjectDisposedException("The stream is closed");
- if (value < 0 || value > (long)Int32.MaxValue || value > capacity)
- throw new ArgumentOutOfRangeException("value that is less than zero, or the position is larger than Int32.MaxValue or capacity of the stream");
- else
- current_position = value;
+ if (value < 0)
+ throw new ArgumentOutOfRangeException("value", "Non-negative number required.");
+ if (value > (long)Int32.MaxValue)
+ throw new ArgumentOutOfRangeException("value", "The position is larger than Int32.MaxValue.");
+ current_position = value;
}
}
+ [CLSCompliantAttribute (false)]
public unsafe byte* PositionPointer {
get {
- throw new NotImplementedException("Error");
+#if NET_4_0
+ if (safebuffer != null)
+ throw new NotSupportedException ("Not supported when using SafeBuffer");
+#endif
+ if (closed)
+ throw new ObjectDisposedException("The stream is closed");
+ if (current_position >= length)
+ throw new IndexOutOfRangeException ("value");
+
+ return (byte *) initial_pointer + current_position;
}
set {
- throw new NotImplementedException("Error");
+#if NET_4_0
+ if (safebuffer != null)
+ throw new NotSupportedException ("Not supported when using SafeBuffer");
+#endif
+ if (closed)
+ throw new ObjectDisposedException("The stream is closed");
+
+ if (value < (byte *)initial_pointer)
+ throw new IOException ("Address is below the inital address");
+
+ Position = value - (byte*) initial_pointer;
}
}
#endregion
#region Methods
public override int Read ([InAttribute] [OutAttribute] byte[] buffer, int offset, int count)
- {
- if (closed)
- throw new ObjectDisposedException("The stream is closed");
-
+ {
+ if (closed)
+ throw new ObjectDisposedException("The stream is closed");
+
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
+ if ((buffer.Length - offset) < count)
+ throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
+
+ if (fileaccess == FileAccess.Write)
+ throw new NotSupportedException("Stream does not support reading");
- if (buffer == null)
- throw new ArgumentNullException("The buffer parameter is set to a null reference");
- if (offset < 0 || count < 0)
- throw new ArgumentOutOfRangeException("The offset or count parameter is less than zero");
- if ((buffer.Length - offset) < count)
- throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
+ if (current_position >= length)
+ return 0;
- if (fileaccess == FileAccess.Write)
- throw new NotSupportedException("Read property is false");
- else {
- if (current_position == capacity)
- return (0);
- else {
- unsafe {
- Marshal.Copy(initial_pointer, buffer, offset,
- (int)length);
- current_position += length;
- }
- return (buffer.GetLength(0));
+ int progress = current_position + count < length ? count : (int) (length - current_position);
+#if NET_4_0
+ if (safebuffer != null) {
+ unsafe {
+ byte *ptr = null;
+ try {
+ safebuffer.AcquirePointer (ref ptr);
+ Marshal.Copy (new IntPtr (ptr + current_position), buffer, offset, progress);
+ } finally {
+ if (ptr != null)
+ safebuffer.ReleasePointer ();
}
}
+ } else
+#endif
+ {
+ Marshal.Copy (new IntPtr (initial_pointer.ToInt64 () + current_position), buffer, offset, progress);
}
- public override int ReadByte () {
+ current_position += progress;
+ return progress;
+ }
+
+ public override int ReadByte ()
+ {
if (closed)
throw new ObjectDisposedException("The stream is closed");
- if (current_position == capacity)
- throw new NotSupportedException("The current position is at the end of the stream");
+
+ if (fileaccess== FileAccess.Write)
+ throw new NotSupportedException("Stream does not support reading");
- int byteread;
+ if (current_position >= length)
+ return (-1);
- if (fileaccess== FileAccess.Write)
- throw new NotSupportedException("The underlying memory does not support reading");
- else {
- if (current_position == length)
- return (-1);
- else {
- unsafe {
- byteread = (int)Marshal.ReadByte(initial_pointer, (int)current_position);
- current_position++;
+#if NET_4_0
+ if (safebuffer != null) {
+ unsafe {
+ byte *ptr = null;
+ try {
+ safebuffer.AcquirePointer (ref ptr);
+ return (int) Marshal.ReadByte (new IntPtr (ptr), (int) current_position++);
+ } finally {
+ if (ptr != null)
+ safebuffer.ReleasePointer ();
}
- return(byteread);
}
+ } else
+#endif
+ {
+ return (int) Marshal.ReadByte(initial_pointer, (int) current_position++);
}
}
- public override long Seek (long offset, SeekOrigin loc) {
+
+ public override long Seek (long offset, SeekOrigin loc)
+ {
if (closed)
throw new ObjectDisposedException("The stream is closed");
- if (offset > capacity)
- throw new ArgumentOutOfRangeException("The offset value is larger than the maximum size of the stream");
+
long refpoint;
switch(loc) {
case SeekOrigin.Begin:
default:
throw new ArgumentException("Invalid SeekOrigin option");
}
- refpoint =+ (int)offset;
+ refpoint += offset;
if (refpoint < initial_position)
throw new IOException("An attempt was made to seek before the beginning of the stream");
current_position = refpoint;
public override void SetLength (long value)
{
+#if NET_4_0
+ if (safebuffer != null)
+ throw new NotSupportedException ("Not supported when using SafeBuffer");
+#endif
if (closed)
throw new ObjectDisposedException("The stream is closed");
- if (value < 0 || value > capacity)
- throw new ArgumentOutOfRangeException("The specified value is negetive exceeds the capacity of the stream");
+ if (value < 0)
+ throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
+ if (value > capacity)
+ throw new IOException ("Unable to expand length of this stream beyond its capacity.");
if (fileaccess == FileAccess.Read)
- throw new NotSupportedException("write property is set to false");
- if (fileaccess == FileAccess.Read)
- throw new NotSupportedException("Length change not supported see object construction");
- else
- length = value;
+ throw new NotSupportedException ("Stream does not support writing.");
+ length = value;
+ if (length < current_position)
+ current_position = length;
}
public override void Flush ()
//but is included as part of the Stream base class
}
- public void Dispose ()
- {
- Dispose(true);
- }
-
protected override void Dispose (bool disposing)
{
-
+ if (closed)
+ return;
closed = true;
+ if (Closed != null)
+ Closed (this, null);
}
public override void Write (byte[] buffer, int offset, int count)
throw new ObjectDisposedException("The stream is closed");
if (buffer == null)
throw new ArgumentNullException("The buffer parameter is a null reference");
- if (count > capacity)
- throw new ArgumentOutOfRangeException("The count value is greater than the capacity of the stream");
- if (offset < 0 || count < 0)
- throw new ArgumentOutOfRangeException("One of the specified parameters is less than zero");
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException("offset", "Non-negative number required.");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count", "Non-negative number required.");
if ((buffer.Length - offset) < count)
throw new ArgumentException("The length of the buffer array minus the offset parameter is less than the count parameter");
+ if (current_position > capacity - count)
+ throw new NotSupportedException ("Unable to expand length of this stream beyond its capacity.");
if (fileaccess == FileAccess.Read)
- throw new NotSupportedException("write property is set to false");
- else {
+ throw new NotSupportedException ("Stream does not support writing.");
+
+#if NET_4_0
+ if (safebuffer != null) {
+ unsafe {
+ byte *dest = null;
+ try {
+ safebuffer.AcquirePointer (ref dest);
+ fixed (byte *src = buffer) {
+ dest += current_position;
+ String.memcpy (dest, src + offset, count);
+ }
+ } finally {
+ if (dest != null)
+ safebuffer.ReleasePointer ();
+ }
+ }
+ } else
+#endif
+ {
unsafe {
- //COPY data from managed buffer to unmanaged mem pointer
- Marshal.Copy(buffer, offset, initial_pointer, (int)length);
- current_position += length;
+ fixed (byte *src = buffer) {
+ byte *dest = (byte *) initial_pointer + current_position;
+ String.memcpy (dest, src + offset, count);
+ }
}
}
+ current_position += count;
+ if (current_position > length)
+ length = current_position;
}
public override void WriteByte (byte value)
- {
+ {
if (closed)
throw new ObjectDisposedException("The stream is closed");
if (current_position == capacity)
throw new NotSupportedException("The current position is at the end of the capacity of the stream");
if (fileaccess == FileAccess.Read)
- throw new NotSupportedException("write property is set to false");
- else {
+ throw new NotSupportedException("Stream does not support writing.");
+
+#if NET_4_0
+ if (safebuffer != null) {
+ unsafe {
+ byte *dest = null;
+ try {
+ safebuffer.AcquirePointer (ref dest);
+ dest += current_position++;
+ *dest = value;
+ } finally {
+ if (dest != null)
+ safebuffer.ReleasePointer ();
+ }
+ }
+ } else
+#endif
+ {
unsafe {
- Marshal.WriteByte(initial_pointer, (int)current_position, value);
- current_position++;
+ byte *dest = (byte *) initial_pointer + (int) current_position++;
+ *dest = value;
}
}
+ if (current_position > length)
+ length = current_position;
}
+
+ [CLSCompliant (false)]
+ protected unsafe void Initialize (byte* pointer, long length,
+ long capacity,
+ FileAccess access)
+ {
+ if (pointer == null)
+ throw new ArgumentNullException("pointer");
+ if (length < 0)
+ throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException("capacity", "Non-negative number required.");
+ if (length > capacity)
+ throw new ArgumentOutOfRangeException("length", "The length cannot be greater than the capacity.");
+ if ((access < FileAccess.Read) || (access > FileAccess.ReadWrite))
+ throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
+ if (!closed)
+ throw new InvalidOperationException ("Called Initialize twice");
+
+ fileaccess = access;
+ this.length = length;
+ this.capacity = capacity;
+ initial_position = 0;
+ current_position = initial_position;
+ initial_pointer = new IntPtr ((void*)pointer);
+ closed = false;
+ }
+
+#if NET_4_0
+ protected void Initialize (SafeBuffer buffer, long offset, long length, FileAccess access)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException ("offset");
+
+ if (length < 0)
+ throw new ArgumentOutOfRangeException ("length");
+
+ ulong blength = buffer.ByteLength;
+ if ((blength - (ulong) length) < (ulong) offset)
+ throw new ArgumentException ("Invalid offset and/or length");
+
+ if (access < FileAccess.Read || access > FileAccess.ReadWrite)
+ throw new ArgumentOutOfRangeException ("access");
+
+ if (!closed)
+ throw new InvalidOperationException ("Called Initialize twice");
+
+ this.length = length;
+ this.capacity = length;
+ this.fileaccess = access;
+ this.safebuffer = buffer;
+ initial_position = offset;
+ current_position = offset;
+ closed = false;
+ }
+#endif
#endregion
}
}
-#endif