Merge pull request #665 from andreas-auerswald/master
[mono.git] / mcs / class / corlib / System.IO / UnmanagedMemoryStream.cs
index f7a0b234999f4f3b283e6f6ed39ffdce614fc384..4083e35d73b7df5f386cbbdeac9177dec5e23208 100644 (file)
@@ -45,6 +45,9 @@ namespace System.IO
                IntPtr initial_pointer;
                long initial_position;
                long current_position;
+#if NET_4_0
+               SafeBuffer safebuffer;
+#endif
                
                internal event EventHandler Closed;
                
@@ -55,17 +58,30 @@ namespace System.IO
                }
 
                [CLSCompliantAttribute(false)]
-               public unsafe UnmanagedMemoryStream (byte *pointer, long length)
+               public unsafe UnmanagedMemoryStream (byte *pointer, long length) :
+                       this (pointer, length, length, FileAccess.Read)
                {
-                       Initialize (pointer, length, length, FileAccess.Read);
                }
                
                [CLSCompliantAttribute(false)]
                public unsafe UnmanagedMemoryStream (byte *pointer, long length, long capacity, 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
@@ -123,6 +139,10 @@ namespace System.IO
                [CLSCompliantAttribute (false)]
                public unsafe byte* PositionPointer {
                        get {
+#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)
@@ -131,6 +151,10 @@ namespace System.IO
                                return (byte *) initial_pointer + current_position;
                        }
                        set {
+#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");
 
@@ -159,16 +183,30 @@ namespace System.IO
                        
                        if (fileaccess == FileAccess.Write)
                                throw new NotSupportedException("Stream does not support reading");
-                       else {
-                               if (current_position >= length)
-                                       return (0);
-                               else {
-                                       int progress = current_position + count < length ? count : (int) (length - current_position);
-                                       for (int i = 0; i < progress; i++)
-                                               buffer [offset + i] = Marshal.ReadByte (initial_pointer, (int) current_position++);
-                                       return progress;
+
+                       if (current_position >= length)
+                               return 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);
                        }
+                       current_position += progress;
+                       return progress;
                }
 
                public override int ReadByte ()
@@ -178,9 +216,25 @@ namespace System.IO
                        
                        if (fileaccess== FileAccess.Write)
                                throw new NotSupportedException("Stream does not support reading");
-                       else {
-                               if (current_position >= length)
-                                       return (-1);
+
+                       if (current_position >= length)
+                               return (-1);
+
+#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 ();
+                                       }
+                               }
+                       } else
+#endif
+                       {
                                return (int) Marshal.ReadByte(initial_pointer, (int) current_position++);
                        }
                }
@@ -215,6 +269,10 @@ namespace System.IO
                 
                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)
@@ -261,17 +319,35 @@ namespace System.IO
                                throw new NotSupportedException ("Unable to expand length of this stream beyond its capacity.");
                        if (fileaccess == FileAccess.Read)
                                throw new NotSupportedException ("Stream does not support writing.");
-                       else {
-                               unsafe {
-                                       // use Marshal.WriteByte since that allow us to start writing
-                                       // from the current position
-                                       for (int i = 0; i < count; i++)
-                                               Marshal.WriteByte (initial_pointer, (int) current_position++, buffer [offset + i]);
 
-                                       if (current_position > length)
-                                               length = current_position;
+#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 {
+                                       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)
@@ -283,14 +359,30 @@ namespace System.IO
                                throw new NotSupportedException("The current position is at the end of the capacity of the stream");
                        if (fileaccess == FileAccess.Read)
                                throw new NotSupportedException("Stream does not support writing.");
-                       else {
+#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++;
-                                       if (current_position > length)
-                                               length = current_position;
+                                       byte *dest = (byte *) initial_pointer + (int) current_position++;
+                                       *dest = value;
                                }
                        }
+                       if (current_position > length)
+                               length = current_position;
                }
 
                [CLSCompliant (false)]
@@ -308,6 +400,8 @@ namespace System.IO
                                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;
@@ -317,6 +411,38 @@ namespace System.IO
                        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
        }
 }