2003-04-19 Ville Palo <vi64pa@kolumbus.fi>
[mono.git] / mcs / class / corlib / System.IO / BufferedStream.cs
1 //
2 // System.IO.BufferedStream
3 //
4 // Author:
5 //   Matt Kimball (matt@kimball.net)
6 //   Ville Palo <vi64pa@kolumbus.fi>
7 //
8
9
10 namespace System.IO {
11         public sealed class BufferedStream : Stream {
12                 Stream m_stream;
13                 byte[] m_buffer;
14                 int m_buffer_pos;
15                 int m_buffer_read_ahead;
16                 bool m_buffer_reading;
17                 private bool disposed = false;
18
19                 public BufferedStream(Stream stream) : this(stream, 4096) {
20                 }
21
22                 public BufferedStream(Stream stream, int buffer_size) {
23
24                         if (stream == null)
25                                 throw new ArgumentNullException ("stream was null");
26                         if (buffer_size < 0)
27                                 throw new ArgumentOutOfRangeException ();
28                         
29                         // if stream is closed this throws an exception FIXME: better way?
30                         {
31                         long l = stream.Position;
32                         }
33                         
34                         m_stream = stream;
35                         m_buffer = new byte[buffer_size];
36                 }
37
38                 public override bool CanRead {
39                         get {
40                                 return m_stream.CanRead;
41                         }
42                 }
43
44                 public override bool CanWrite {
45                         get {
46                                 return m_stream.CanWrite;
47                         }
48                 }
49
50                 public override bool CanSeek {
51                         get {
52                                 return m_stream.CanSeek;
53                         }
54                 }
55
56                 public override long Length {
57                         get {                           
58                                 Flush ();
59                                 return m_stream.Length;
60                         }
61                 }
62                 
63                 public override long Position {
64                         get {
65                                 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
66                         }
67
68                         set {
69                                 Flush();
70                                 m_stream.Position = value;
71                         }
72                 }
73
74                 public override void Close() {
75                         Flush();
76                         m_stream.Close();
77                         m_buffer = null;
78                         disposed = true;
79                 }
80
81                 public override void Flush() {
82                         
83                         if (m_buffer_reading) {
84                                 if (CanSeek)
85                                         m_stream.Position = Position;
86                         } else if (m_buffer_pos > 0) {
87                                 m_stream.Write(m_buffer, 0, m_buffer_pos);
88                         }
89
90                         m_buffer_read_ahead = 0;
91                         m_buffer_pos = 0;
92                 }
93
94                 public override long Seek(long offset, SeekOrigin origin) {
95                         Flush();
96                         return m_stream.Seek(offset, origin);
97                 }
98
99                 public override void SetLength(long value) {
100                         m_stream.SetLength(value);
101                 }
102
103                 public override int ReadByte() {
104
105                         CheckObjectDisposedException ();
106                         
107                         byte[] b = new byte[1];
108
109                         if (Read(b, 0, 1) == 1) {
110                                 return b[0];
111                         } else {
112                                 return -1;
113                         }
114                 }
115
116                 public override void WriteByte(byte value) {
117
118                         CheckObjectDisposedException ();
119                         byte[] b = new byte[1];
120
121                         b[0] = value;
122                         Write(b, 0, 1);
123                 }
124
125                 public override int Read(byte[] array, int offset, int count) {
126
127                         CheckObjectDisposedException ();
128
129                         if (array.Length < offset + count)
130                                 throw new ArgumentException ();
131                         if (offset < 0)
132                                 throw new ArgumentOutOfRangeException ("Offset was negative value.");
133
134                         if (!m_buffer_reading) {
135                                 Flush();
136                                 m_buffer_reading = true;
137                         }
138
139                         if (count <= m_buffer_read_ahead - m_buffer_pos) {
140                                 Array.Copy(m_buffer, m_buffer_pos, array, offset, count);
141
142                                 m_buffer_pos += count;
143                                 if (m_buffer_pos == m_buffer_read_ahead) {
144                                         m_buffer_pos = 0;
145                                         m_buffer_read_ahead = 0;
146                                 }
147
148                                 return count;
149                         }
150
151                         int ret = m_buffer_read_ahead - m_buffer_pos;
152                         Array.Copy(m_buffer, m_buffer_pos, array, offset, ret);
153                         m_buffer_pos = 0;
154                         m_buffer_read_ahead = 0;
155                         offset += ret;
156                         count -= ret;
157
158                         if (count >= m_buffer.Length) {
159                                 ret += m_stream.Read(array, offset, count);
160                         } else {
161                                 m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
162                                 
163                                 if (count < m_buffer_read_ahead) {
164                                         Array.Copy(m_buffer, 0, array, offset, count);
165                                         m_buffer_pos = count;
166                                         ret += count;
167                                 } else {
168                                         Array.Copy(m_buffer, 0, array, offset, m_buffer_read_ahead);
169                                         ret += m_buffer_read_ahead;
170                                         m_buffer_read_ahead = 0;
171                                 }
172                         }
173
174                         return ret;
175                 }
176
177                 public override void Write(byte[] array, int offset, int count) {
178
179                         CheckObjectDisposedException ();
180
181                         if (!m_stream.CanRead)
182                                 throw new NotSupportedException ();
183                         if (offset < 0)
184                                 throw new ArgumentOutOfRangeException ();
185
186                         if (m_buffer_reading) {
187                                 Flush();
188                                 m_buffer_reading = false;
189                         }
190
191                         if (m_buffer_pos + count >= m_buffer.Length) {
192                                 Flush();
193                                 m_stream.Write(array, offset, count);
194                         } else {
195                                 Array.Copy(array, offset, m_buffer, m_buffer_pos, count);
196                                 m_buffer_pos += count;
197                         }
198                 }
199
200                 private void CheckObjectDisposedException () 
201                 {
202                         if (disposed) 
203                                 throw new ObjectDisposedException ("BufferedStream", "Stream is closed");
204                 }                       
205         }
206 }