**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / System.IO / BufferedStream.cs
blob1fa7931f78a1b6bcce3e9bba0f60595fd23e3eda
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 public sealed class BufferedStream : Stream {
39 Stream m_stream;
40 byte[] m_buffer;
41 int m_buffer_pos;
42 int m_buffer_read_ahead;
43 bool m_buffer_reading;
44 private bool disposed = false;
46 public BufferedStream (Stream stream) : this (stream, 4096)
50 public BufferedStream (Stream stream, int buffer_size)
52 if (stream == null)
53 throw new ArgumentNullException ("stream");
54 // LAMESPEC: documented as < 0
55 if (buffer_size <= 0)
56 throw new ArgumentOutOfRangeException ("buffer_size", "<= 0");
57 if (!stream.CanRead && !stream.CanWrite) {
58 throw new ObjectDisposedException (
59 Locale.GetText ("Cannot access a closed Stream."));
62 m_stream = stream;
63 m_buffer = new byte [buffer_size];
66 public override bool CanRead {
67 get {
68 return m_stream.CanRead;
72 public override bool CanWrite {
73 get {
74 return m_stream.CanWrite;
78 public override bool CanSeek {
79 get {
80 return m_stream.CanSeek;
84 public override long Length {
85 get {
86 Flush ();
87 return m_stream.Length;
91 public override long Position {
92 get {
93 CheckObjectDisposedException ();
94 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
97 set {
98 if (value < Position && (Position - value <= m_buffer_pos) && m_buffer_reading) {
99 m_buffer_pos -= (int) (Position - value);
101 else if (value > Position && (value - Position < m_buffer_read_ahead - m_buffer_pos) && m_buffer_reading) {
102 m_buffer_pos += (int) (value - Position);
104 else {
105 Flush();
106 m_stream.Position = value;
111 public override void Close ()
113 if (m_buffer != null)
114 Flush();
116 m_stream.Close();
117 m_buffer = null;
118 disposed = true;
121 public override void Flush ()
123 CheckObjectDisposedException ();
125 if (m_buffer_reading) {
126 if (CanSeek)
127 m_stream.Position = Position;
128 } else if (m_buffer_pos > 0) {
129 m_stream.Write(m_buffer, 0, m_buffer_pos);
132 m_buffer_read_ahead = 0;
133 m_buffer_pos = 0;
136 public override long Seek (long offset, SeekOrigin origin)
138 CheckObjectDisposedException ();
139 if (!CanSeek) {
140 throw new NotSupportedException (
141 Locale.GetText ("Non seekable stream."));
143 Flush ();
144 return m_stream.Seek (offset, origin);
147 public override void SetLength (long value)
149 CheckObjectDisposedException ();
151 if (value < 0)
152 throw new ArgumentOutOfRangeException ("value must be positive");
154 if (!m_stream.CanWrite && !m_stream.CanSeek)
155 throw new NotSupportedException ("the stream cannot seek nor write.");
157 if ((m_stream == null) || (!m_stream.CanRead && !m_stream.CanWrite))
158 throw new IOException ("the stream is not open");
160 m_stream.SetLength(value);
161 if (Position > value)
162 Position = value;
165 public override int ReadByte ()
167 CheckObjectDisposedException ();
169 byte[] b = new byte[1];
171 if (Read(b, 0, 1) == 1) {
172 return b[0];
173 } else {
174 return -1;
178 public override void WriteByte (byte value)
180 CheckObjectDisposedException ();
181 byte[] b = new byte[1];
183 b[0] = value;
184 Write(b, 0, 1);
187 public override int Read ([In,Out] byte[] array, int offset, int count)
189 if (array == null)
190 throw new ArgumentNullException ("array");
191 CheckObjectDisposedException ();
192 if (!m_stream.CanRead) {
193 throw new NotSupportedException (
194 Locale.GetText ("Cannot read from stream"));
196 if (offset < 0)
197 throw new ArgumentOutOfRangeException ("offset", "< 0");
198 if (count < 0)
199 throw new ArgumentOutOfRangeException ("count", "< 0");
200 // re-ordered to avoid possible integer overflow
201 if (array.Length - offset < count)
202 throw new ArgumentException ("array.Length - offset < count");
204 if (!m_buffer_reading) {
205 Flush();
206 m_buffer_reading = true;
209 if (count <= m_buffer_read_ahead - m_buffer_pos) {
210 Array.Copy(m_buffer, m_buffer_pos, array, offset, count);
212 m_buffer_pos += count;
213 if (m_buffer_pos == m_buffer_read_ahead) {
214 m_buffer_pos = 0;
215 m_buffer_read_ahead = 0;
218 return count;
221 int ret = m_buffer_read_ahead - m_buffer_pos;
222 Array.Copy(m_buffer, m_buffer_pos, array, offset, ret);
223 m_buffer_pos = 0;
224 m_buffer_read_ahead = 0;
225 offset += ret;
226 count -= ret;
228 if (count >= m_buffer.Length) {
229 ret += m_stream.Read(array, offset, count);
230 } else {
231 m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
233 if (count < m_buffer_read_ahead) {
234 Array.Copy(m_buffer, 0, array, offset, count);
235 m_buffer_pos = count;
236 ret += count;
237 } else {
238 Array.Copy(m_buffer, 0, array, offset, m_buffer_read_ahead);
239 ret += m_buffer_read_ahead;
240 m_buffer_read_ahead = 0;
244 return ret;
247 public override void Write (byte[] array, int offset, int count)
249 if (array == null)
250 throw new ArgumentNullException ("array");
251 CheckObjectDisposedException ();
252 if (!m_stream.CanWrite) {
253 throw new NotSupportedException (
254 Locale.GetText ("Cannot write to stream"));
256 if (offset < 0)
257 throw new ArgumentOutOfRangeException ("offset", "< 0");
258 if (count < 0)
259 throw new ArgumentOutOfRangeException ("count", "< 0");
260 // avoid possible integer overflow
261 if (array.Length - offset < count)
262 throw new ArgumentException ("array.Length - offset < count");
264 if (m_buffer_reading) {
265 Flush();
266 m_buffer_reading = false;
269 // reordered to avoid possible integer overflow
270 if (m_buffer_pos >= m_buffer.Length - count) {
271 Flush ();
272 m_stream.Write (array, offset, count);
274 else {
275 Array.Copy (array, offset, m_buffer, m_buffer_pos, count);
276 m_buffer_pos += count;
280 private void CheckObjectDisposedException ()
282 if (disposed) {
283 throw new ObjectDisposedException ("BufferedStream",
284 Locale.GetText ("Stream is closed"));