2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.IO / BufferedStream.cs
index cdfe41c43a364f533a318214d4b592c468df8a02..ab8bcd831d814ed138cc164b81e238a5eb238a02 100644 (file)
@@ -5,7 +5,33 @@
 //   Matt Kimball (matt@kimball.net)
 //   Ville Palo <vi64pa@kolumbus.fi>
 //
+// Copyright (C) 2004 Novell (http://www.novell.com)
+//
+
+//
+// Copyright (C) 2004 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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 
+using System.Globalization;
 using System.Runtime.InteropServices;
 
 namespace System.IO {
@@ -17,20 +43,24 @@ namespace System.IO {
                bool m_buffer_reading;
                private bool disposed = false;
 
-               public BufferedStream(Stream stream) : this(stream, 4096) {
+               public BufferedStream (Stream stream) : this (stream, 4096) 
+               {
                }
 
-               public BufferedStream(Stream stream, int buffer_size) {
-
+               public BufferedStream (Stream stream, int buffer_size) 
+               {
                        if (stream == null)
-                               throw new ArgumentNullException ("stream was null");
-                       if (buffer_size < 0)
-                               throw new ArgumentOutOfRangeException ();
-                       if (!stream.CanRead && !stream.CanWrite)
-                               throw new ObjectDisposedException ("Cannot access a closed Stream.");
+                               throw new ArgumentNullException ("stream");
+                       // LAMESPEC: documented as < 0
+                       if (buffer_size <= 0)
+                               throw new ArgumentOutOfRangeException ("buffer_size", "<= 0");
+                       if (!stream.CanRead && !stream.CanWrite) {
+                               throw new ObjectDisposedException (
+                                       Locale.GetText ("Cannot access a closed Stream."));
+                       }
 
                        m_stream = stream;
-                       m_buffer = new byte[buffer_size];
+                       m_buffer = new byte [buffer_size];
                }
 
                public override bool CanRead {
@@ -78,8 +108,8 @@ namespace System.IO {
                        }
                }
 
-               public override void Close() {
-                       
+               public override void Close ()
+               {
                        if (m_buffer != null)
                                Flush();
 
@@ -88,8 +118,8 @@ namespace System.IO {
                        disposed = true;
                }
 
-               public override void Flush() {
-                       
+               public override void Flush ()
+               {
                        CheckObjectDisposedException ();
 
                        if (m_buffer_reading) {
@@ -103,17 +133,37 @@ namespace System.IO {
                        m_buffer_pos = 0;
                }
 
-               public override long Seek(long offset, SeekOrigin origin) {
-                       Flush();
-                       return m_stream.Seek(offset, origin);
+               public override long Seek (long offset, SeekOrigin origin)
+               {
+                       CheckObjectDisposedException ();
+                       if (!CanSeek) {
+                               throw new NotSupportedException (
+                                       Locale.GetText ("Non seekable stream."));
+                       }
+                       Flush ();
+                       return m_stream.Seek (offset, origin);
                }
 
-               public override void SetLength(long value) {
+               public override void SetLength (long value)
+               {
+                       CheckObjectDisposedException ();
+
+                       if (value < 0)
+                               throw new ArgumentOutOfRangeException ("value must be positive");
+
+                       if (!m_stream.CanWrite && !m_stream.CanSeek)
+                               throw new NotSupportedException ("the stream cannot seek nor write.");
+
+                       if ((m_stream == null) || (!m_stream.CanRead && !m_stream.CanWrite))
+                               throw new IOException ("the stream is not open");
+                       
                        m_stream.SetLength(value);
+                       if (Position > value)
+                               Position = value;
                }
 
-               public override int ReadByte() {
-
+               public override int ReadByte ()
+               {
                        CheckObjectDisposedException ();
                        
                        byte[] b = new byte[1];
@@ -125,8 +175,8 @@ namespace System.IO {
                        }
                }
 
-               public override void WriteByte(byte value) {
-
+               public override void WriteByte (byte value) 
+               {
                        CheckObjectDisposedException ();
                        byte[] b = new byte[1];
 
@@ -134,14 +184,22 @@ namespace System.IO {
                        Write(b, 0, 1);
                }
 
-               public override int Read([In,Out] byte[] array, int offset, int count) {
-
+               public override int Read ([In,Out] byte[] array, int offset, int count) 
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        CheckObjectDisposedException ();
-
-                       if (array.Length < offset + count)
-                               throw new ArgumentException ();
+                       if (!m_stream.CanRead) {
+                               throw new NotSupportedException (
+                                       Locale.GetText ("Cannot read from stream"));
+                       }
                        if (offset < 0)
-                               throw new ArgumentOutOfRangeException ("Offset was negative value.");
+                               throw new ArgumentOutOfRangeException ("offset", "< 0");
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "< 0");
+                       // re-ordered to avoid possible integer overflow
+                       if (array.Length - offset < count)
+                               throw new ArgumentException ("array.Length - offset < count");
 
                        if (!m_buffer_reading) {
                                Flush();
@@ -149,7 +207,7 @@ namespace System.IO {
                        }
 
                        if (count <= m_buffer_read_ahead - m_buffer_pos) {
-                               Array.Copy(m_buffer, m_buffer_pos, array, offset, count);
+                               Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, count);
 
                                m_buffer_pos += count;
                                if (m_buffer_pos == m_buffer_read_ahead) {
@@ -161,7 +219,7 @@ namespace System.IO {
                        }
 
                        int ret = m_buffer_read_ahead - m_buffer_pos;
-                       Array.Copy(m_buffer, m_buffer_pos, array, offset, ret);
+                       Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, ret);
                        m_buffer_pos = 0;
                        m_buffer_read_ahead = 0;
                        offset += ret;
@@ -173,11 +231,11 @@ namespace System.IO {
                                m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
                                
                                if (count < m_buffer_read_ahead) {
-                                       Array.Copy(m_buffer, 0, array, offset, count);
+                                       Buffer.BlockCopyInternal (m_buffer, 0, array, offset, count);
                                        m_buffer_pos = count;
                                        ret += count;
                                } else {
-                                       Array.Copy(m_buffer, 0, array, offset, m_buffer_read_ahead);
+                                       Buffer.BlockCopyInternal (m_buffer, 0, array, offset, m_buffer_read_ahead);
                                        ret += m_buffer_read_ahead;
                                        m_buffer_read_ahead = 0;
                                }
@@ -186,33 +244,45 @@ namespace System.IO {
                        return ret;
                }
 
-               public override void Write(byte[] array, int offset, int count) {
-
+               public override void Write (byte[] array, int offset, int count)
+               {
+                       if (array == null)
+                               throw new ArgumentNullException ("array");
                        CheckObjectDisposedException ();
-
-                       if (!m_stream.CanWrite)
-                               throw new NotSupportedException ();
+                       if (!m_stream.CanWrite) {
+                               throw new NotSupportedException (
+                                       Locale.GetText ("Cannot write to stream"));
+                       }
                        if (offset < 0)
-                               throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ("offset", "< 0");
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", "< 0");
+                       // avoid possible integer overflow
+                       if (array.Length - offset < count)
+                               throw new ArgumentException ("array.Length - offset < count");
 
                        if (m_buffer_reading) {
                                Flush();
                                m_buffer_reading = false;
                        }
 
-                       if (m_buffer_pos + count >= m_buffer.Length) {
-                               Flush();
-                               m_stream.Write(array, offset, count);
-                       } else {
-                               Array.Copy(array, offset, m_buffer, m_buffer_pos, count);
+                       // reordered to avoid possible integer overflow
+                       if (m_buffer_pos >= m_buffer.Length - count) {
+                               Flush ();
+                               m_stream.Write (array, offset, count);
+                       } 
+                       else {
+                               Buffer.BlockCopyInternal  (array, offset, m_buffer, m_buffer_pos, count);
                                m_buffer_pos += count;
                        }
                }
 
                private void CheckObjectDisposedException () 
                {
-                       if (disposed) 
-                               throw new ObjectDisposedException ("BufferedStream", "Stream is closed");
-               }                       
+                       if (disposed) {
+                               throw new ObjectDisposedException ("BufferedStream", 
+                                       Locale.GetText ("Stream is closed"));
+                       }
+               }
        }
 }