2008-01-15 Stephane Delcroix <sdelcroix@novell.com>
[mono.git] / mcs / class / corlib / System.IO / UnmanagedMemoryStream.cs
index 2bec7e0739e82f5d39ebb3112d5324fb4710bcdb..4342766f6c120bcbe1a175d96648d61e9b0863c3 100644 (file)
@@ -1,14 +1,11 @@
-//------------------------------------------------------------------------------
 //
 // 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)
 //
 // Copyright (C) 2005-2006 Novell, Inc (http://www.novell.com)
 //
@@ -38,7 +35,6 @@ using System;
 using System.IO;
 using System.Runtime.InteropServices;
 
-
 namespace System.IO
 {
        [CLSCompliantAttribute(false)]
@@ -54,6 +50,8 @@ namespace System.IO
                long initial_position;
                long current_position;
                
+               internal event EventHandler Closed;
+               
 #region Constructor
                protected UnmanagedMemoryStream()
                {
@@ -64,15 +62,15 @@ namespace System.IO
                        current_position = initial_position;
                }
                
-               public unsafe UnmanagedMemoryStream (byte *pointer, long len)
+               public unsafe UnmanagedMemoryStream (byte *pointer, long length)
                {
                        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");
+                               throw new ArgumentNullException("pointer");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
                        fileaccess = FileAccess.Read;
-                       length = len;
-                       capacity = len;
+                       this.length = length;
+                       capacity = length;
                        initial_position = 0;
                        current_position = initial_position;
                        canseek = true;
@@ -80,19 +78,21 @@ namespace System.IO
                        initial_pointer = new IntPtr((void*)pointer);
                }
                
-               public unsafe UnmanagedMemoryStream (byte *pointer, long len, long cap, FileAccess access)
+               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");
+                               throw new ArgumentNullException("pointer");
+                       if (length < 0)
+                               throw new ArgumentOutOfRangeException("length", "Non-negative number required.");
                        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");
+                               throw new ArgumentOutOfRangeException("capacity", "Non-negative number required.");
+                       if (length > capacity)
+                               throw new ArgumentOutOfRangeException("length", "The length cannot be greater than the capacity.");
+                       if (!Enum.IsDefined (typeof (FileAccess), access))
+                               throw new ArgumentOutOfRangeException ("access", "Enum value was out of legal range.");
                        fileaccess = access;
-                       length = len;
-                       capacity = cap;
+                       this.length = length;
+                       this.capacity = capacity;
                        initial_position = 0;
                        current_position = initial_position;
                        canseek = true;
@@ -107,14 +107,13 @@ namespace System.IO
                        get {
                                if (closed)
                                        return false;
-                               else
-                                       return ((fileaccess == FileAccess.Read || fileaccess == FileAccess.ReadWrite)? true:false);
+                               return (fileaccess == FileAccess.Read || fileaccess == FileAccess.ReadWrite);
                        }
                }
 
                public override bool CanSeek {
                        get {
-                               return ((closed) ? false : true);
+                               return !closed;
                        }
                }
                
@@ -122,8 +121,7 @@ namespace System.IO
                        get {
                                if (closed)
                                        return (false);
-                               else
-                                       return ((fileaccess == FileAccess.Write || fileaccess == FileAccess.ReadWrite)? true:false);
+                               return (fileaccess == FileAccess.Write || fileaccess == FileAccess.ReadWrite);
                        }
                }
                public long Capacity {
@@ -146,16 +144,16 @@ namespace System.IO
                        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;
                        }
                }
 
@@ -175,56 +173,44 @@ namespace System.IO
                                if (closed)
                                        throw new ObjectDisposedException("The stream is closed");
 
-
                                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");
+                                       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("Read property is false");
+                                       throw new NotSupportedException("Stream does not support reading");
                                else {
-                                       if (current_position == capacity)
+                                       if (current_position >= length)
                                                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);
+                                               for (int i = 0; i < progress; i++)
+                                                       buffer [offset + i] = Marshal.ReadByte (initial_pointer, (int) current_position++);
+                                               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");
-
-                       int byteread;
 
                        if (fileaccess== FileAccess.Write)
-                               throw new NotSupportedException("The underlying memory does not support reading");
+                               throw new NotSupportedException("Stream does not support reading");
                        else {
-                               if (current_position == length)
+                               if (current_position >= length)
                                        return (-1);
-                               else {
-                                       unsafe {
-                                               byteread = (int)Marshal.ReadByte(initial_pointer, (int)current_position);
-                                               current_position++;
-                                       }
-                                       return(byteread);
-                               }
+                               return (int) Marshal.ReadByte(initial_pointer, (int) current_position++);
                        }
                }
                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:
@@ -241,7 +227,7 @@ namespace System.IO
                        default:
                                throw new ArgumentException("Invalid SeekOrigin option");
                        }
-                       refpoint =+ (int)offset;
+                       refpoint += (int)offset;
                        if (refpoint < initial_position)
                                throw new IOException("An attempt was made to seek before the beginning of the stream");
                        current_position = refpoint;
@@ -252,14 +238,15 @@ namespace System.IO
                {
                        if (closed)
                                throw new ObjectDisposedException("The stream is closed");
-                       if (value < 0 || value > capacity)
-                               throw new ArgumentOutOfRangeException("The specified value is negative or exceeds the capacity of the stream");
-                       if (fileaccess == FileAccess.Read)
-                               throw new NotSupportedException("write property is set to false");
+                       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("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 ()
@@ -272,8 +259,11 @@ namespace System.IO
                 
                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)
@@ -282,19 +272,25 @@ namespace System.IO
                                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 ((current_position + count) > capacity)
+                               throw new NotSupportedException ("Unable to expand length of this stream beyond its capacity.");
+                       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.Read)
-                               throw new NotSupportedException("write property is set to false");
+                               throw new NotSupportedException ("Stream does not support writing.");
                        else {
                                unsafe {
-                                       //COPY data from managed buffer to unmanaged mem pointer
-                                       Marshal.Copy(buffer, offset, initial_pointer, (int)length);
-                                       current_position += length;
+                                       // 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;
                                }
                        }
                }
@@ -307,11 +303,13 @@ namespace System.IO
                        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");
+                               throw new NotSupportedException("Stream does not support writing.");
                        else {
                                unsafe {
                                        Marshal.WriteByte(initial_pointer, (int)current_position, value);
                                        current_position++;
+                                       if (current_position > length)
+                                               length = current_position;
                                }
                        }
                }