2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.IO / BufferedStream.cs
blobe5b68c4c05fbcd57071343496e9aa3c06589aa5d
1 //
2 // System.IO.BufferedStream
3 //
4 // Author:
5 // Matt Kimball (matt@kimball.net)
6 // Ville Palo <vi64pa@kolumbus.fi>
7 //
8 // Copyright (C) 2004 Novell (http://www.novell.com)
9 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Globalization;
35 using System.Runtime.InteropServices;
37 namespace System.IO {
38 [ComVisible (true)]
39 public sealed class BufferedStream : Stream {
40 Stream m_stream;
41 byte[] m_buffer;
42 int m_buffer_pos;
43 int m_buffer_read_ahead;
44 bool m_buffer_reading;
45 private bool disposed = false;
47 public BufferedStream (Stream stream) : this (stream, 4096)
51 public BufferedStream (Stream stream, int bufferSize)
53 if (stream == null)
54 throw new ArgumentNullException ("stream");
55 // LAMESPEC: documented as < 0
56 if (bufferSize <= 0)
57 throw new ArgumentOutOfRangeException ("bufferSize", "<= 0");
58 if (!stream.CanRead && !stream.CanWrite) {
59 throw new ObjectDisposedException (
60 Locale.GetText ("Cannot access a closed Stream."));
63 m_stream = stream;
64 m_buffer = new byte [bufferSize];
67 public override bool CanRead {
68 get {
69 return m_stream.CanRead;
73 public override bool CanWrite {
74 get {
75 return m_stream.CanWrite;
79 public override bool CanSeek {
80 get {
81 return m_stream.CanSeek;
85 public override long Length {
86 get {
87 Flush ();
88 return m_stream.Length;
92 public override long Position {
93 get {
94 CheckObjectDisposedException ();
95 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
98 set {
99 if (value < Position && (Position - value <= m_buffer_pos) && m_buffer_reading) {
100 m_buffer_pos -= (int) (Position - value);
102 else if (value > Position && (value - Position < m_buffer_read_ahead - m_buffer_pos) && m_buffer_reading) {
103 m_buffer_pos += (int) (value - Position);
105 else {
106 Flush();
107 m_stream.Position = value;
112 protected override void Dispose (bool disposing)
114 if (disposed)
115 return;
116 if (m_buffer != null)
117 Flush();
119 m_stream.Close();
120 m_buffer = null;
121 disposed = true;
124 public override void Flush ()
126 CheckObjectDisposedException ();
128 if (m_buffer_reading) {
129 if (CanSeek)
130 m_stream.Position = Position;
131 } else if (m_buffer_pos > 0) {
132 m_stream.Write(m_buffer, 0, m_buffer_pos);
135 m_buffer_read_ahead = 0;
136 m_buffer_pos = 0;
139 public override long Seek (long offset, SeekOrigin origin)
141 CheckObjectDisposedException ();
142 if (!CanSeek) {
143 throw new NotSupportedException (
144 Locale.GetText ("Non seekable stream."));
146 Flush ();
147 return m_stream.Seek (offset, origin);
150 public override void SetLength (long value)
152 CheckObjectDisposedException ();
154 if (value < 0)
155 throw new ArgumentOutOfRangeException ("value must be positive");
157 if (!m_stream.CanWrite && !m_stream.CanSeek)
158 throw new NotSupportedException ("the stream cannot seek nor write.");
160 if ((m_stream == null) || (!m_stream.CanRead && !m_stream.CanWrite))
161 throw new IOException ("the stream is not open");
163 m_stream.SetLength(value);
164 if (Position > value)
165 Position = value;
168 public override int ReadByte ()
170 CheckObjectDisposedException ();
172 if (!m_stream.CanRead) {
173 throw new NotSupportedException (
174 Locale.GetText ("Cannot read from stream"));
177 if (!m_buffer_reading) {
178 Flush ();
179 m_buffer_reading = true;
182 if (1 <= m_buffer_read_ahead - m_buffer_pos) {
183 return m_buffer [m_buffer_pos++];
185 else
187 if (m_buffer_pos >= m_buffer_read_ahead) {
188 m_buffer_pos = 0;
189 m_buffer_read_ahead = 0;
192 m_buffer_read_ahead = m_stream.Read (m_buffer, 0, m_buffer.Length);
193 if (1 <= m_buffer_read_ahead) {
194 return m_buffer [m_buffer_pos++];
195 } else {
196 return -1;
201 public override void WriteByte (byte value)
203 CheckObjectDisposedException ();
204 if (!m_stream.CanWrite) {
205 throw new NotSupportedException (
206 Locale.GetText ("Cannot write to stream"));
209 if (m_buffer_reading) {
210 Flush ();
211 m_buffer_reading = false;
213 else
214 // reordered to avoid possible integer overflow
215 if (m_buffer_pos >= m_buffer.Length - 1) {
216 Flush ();
219 m_buffer [m_buffer_pos++] = value;
222 public override int Read ([In,Out] byte[] array, int offset, int count)
224 if (array == null)
225 throw new ArgumentNullException ("array");
226 CheckObjectDisposedException ();
227 if (!m_stream.CanRead) {
228 throw new NotSupportedException (
229 Locale.GetText ("Cannot read from stream"));
231 if (offset < 0)
232 throw new ArgumentOutOfRangeException ("offset", "< 0");
233 if (count < 0)
234 throw new ArgumentOutOfRangeException ("count", "< 0");
235 // re-ordered to avoid possible integer overflow
236 if (array.Length - offset < count)
237 throw new ArgumentException ("array.Length - offset < count");
239 if (!m_buffer_reading) {
240 Flush();
241 m_buffer_reading = true;
244 if (count <= m_buffer_read_ahead - m_buffer_pos) {
245 Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, count);
247 m_buffer_pos += count;
248 if (m_buffer_pos == m_buffer_read_ahead) {
249 m_buffer_pos = 0;
250 m_buffer_read_ahead = 0;
253 return count;
256 int ret = m_buffer_read_ahead - m_buffer_pos;
257 Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, ret);
258 m_buffer_pos = 0;
259 m_buffer_read_ahead = 0;
260 offset += ret;
261 count -= ret;
263 if (count >= m_buffer.Length) {
264 ret += m_stream.Read (array, offset, count);
265 } else {
266 m_buffer_read_ahead = m_stream.Read (m_buffer, 0, m_buffer.Length);
268 if (count < m_buffer_read_ahead) {
269 Buffer.BlockCopyInternal (m_buffer, 0, array, offset, count);
270 m_buffer_pos = count;
271 ret += count;
272 } else {
273 Buffer.BlockCopyInternal (m_buffer, 0, array, offset, m_buffer_read_ahead);
274 ret += m_buffer_read_ahead;
275 m_buffer_read_ahead = 0;
279 return ret;
282 public override void Write (byte[] array, int offset, int count)
284 if (array == null)
285 throw new ArgumentNullException ("array");
286 CheckObjectDisposedException ();
287 if (!m_stream.CanWrite) {
288 throw new NotSupportedException (
289 Locale.GetText ("Cannot write to stream"));
291 if (offset < 0)
292 throw new ArgumentOutOfRangeException ("offset", "< 0");
293 if (count < 0)
294 throw new ArgumentOutOfRangeException ("count", "< 0");
295 // avoid possible integer overflow
296 if (array.Length - offset < count)
297 throw new ArgumentException ("array.Length - offset < count");
299 if (m_buffer_reading) {
300 Flush();
301 m_buffer_reading = false;
304 // reordered to avoid possible integer overflow
305 if (m_buffer_pos >= m_buffer.Length - count) {
306 Flush ();
307 m_stream.Write (array, offset, count);
309 else {
310 Buffer.BlockCopyInternal (array, offset, m_buffer, m_buffer_pos, count);
311 m_buffer_pos += count;
315 private void CheckObjectDisposedException ()
317 if (disposed) {
318 throw new ObjectDisposedException ("BufferedStream",
319 Locale.GetText ("Stream is closed"));