2004-06-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / corlib / System.IO / BufferedStream.cs
index 12039be8b759737fea07e520da5d558338dd3ce9..d70ad125374d8e875aa5279c474bf3ec635a0eb2 100644 (file)
@@ -3,7 +3,13 @@
 //
 // Author:
 //   Matt Kimball (matt@kimball.net)
+//   Ville Palo <vi64pa@kolumbus.fi>
 //
+// Copyright (C) 2004 Novell (http://www.novell.com)
+//
+
+using System.Globalization;
+using System.Runtime.InteropServices;
 
 namespace System.IO {
        public sealed class BufferedStream : Stream {
@@ -12,13 +18,26 @@ namespace System.IO {
                int m_buffer_pos;
                int m_buffer_read_ahead;
                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");
+                       // 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 {
@@ -40,33 +59,50 @@ namespace System.IO {
                }
 
                public override long Length {
-                       get {
+                       get {                           
+                               Flush ();
                                return m_stream.Length;
                        }
                }
                
                public override long Position {
                        get {
+                               CheckObjectDisposedException ();
                                return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
                        }
 
                        set {
-                               Flush();
-                               m_stream.Position = value;
+                               if (value < Position && (Position - value <= m_buffer_pos) && m_buffer_reading) {
+                                       m_buffer_pos -= (int) (Position - value);
+                               }
+                               else if (value > Position && (value - Position < m_buffer_read_ahead - m_buffer_pos) && m_buffer_reading) {
+                                       m_buffer_pos += (int) (value - Position);
+                               }
+                               else {
+                                       Flush();
+                                       m_stream.Position = value;
+                               }
                        }
                }
 
-               public override void Close() {
-                       Flush();
+               public override void Close ()
+               {
+                       if (m_buffer != null)
+                               Flush();
+
                        m_stream.Close();
-                       m_stream = null;
                        m_buffer = null;
+                       disposed = true;
                }
 
-               public override void Flush() {
+               public override void Flush ()
+               {
+                       CheckObjectDisposedException ();
+
                        if (m_buffer_reading) {
-                               m_stream.Position = Position;
-                       } else {
+                               if (CanSeek)
+                                       m_stream.Position = Position;
+                       } else if (m_buffer_pos > 0) {
                                m_stream.Write(m_buffer, 0, m_buffer_pos);
                        }
 
@@ -74,16 +110,29 @@ 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 ();
                        m_stream.SetLength(value);
+                       if (Position > value)
+                               Position = value;
                }
 
-               public override int ReadByte() {
+               public override int ReadByte ()
+               {
+                       CheckObjectDisposedException ();
+                       
                        byte[] b = new byte[1];
 
                        if (Read(b, 0, 1) == 1) {
@@ -93,14 +142,32 @@ namespace System.IO {
                        }
                }
 
-               public override void WriteByte(byte value) {
+               public override void WriteByte (byte value) 
+               {
+                       CheckObjectDisposedException ();
                        byte[] b = new byte[1];
 
                        b[0] = value;
                        Write(b, 0, 1);
                }
 
-               public override int Read(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 (!m_stream.CanRead) {
+                               throw new NotSupportedException (
+                                       Locale.GetText ("Cannot read from stream"));
+                       }
+                       if (offset < 0)
+                               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();
                                m_buffer_reading = true;
@@ -144,19 +211,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 (
+                                       Locale.GetText ("Cannot write to stream"));
+                       }
+                       if (offset < 0)
+                               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 {
+                               Array.Copy (array, offset, m_buffer, m_buffer_pos, count);
                                m_buffer_pos += count;
                        }
                }
+
+               private void CheckObjectDisposedException () 
+               {
+                       if (disposed) {
+                               throw new ObjectDisposedException ("BufferedStream", 
+                                       Locale.GetText ("Stream is closed"));
+                       }
+               }                       
        }
 }