2 // System.IO.BufferedStream
5 // Matt Kimball (matt@kimball.net)
6 // Ville Palo <vi64pa@kolumbus.fi>
8 // Copyright (C) 2004 Novell (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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;
39 public sealed class BufferedStream : Stream {
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)
54 throw new ArgumentNullException ("stream");
55 // LAMESPEC: documented as < 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."));
64 m_buffer = new byte [bufferSize];
67 public override bool CanRead {
69 return m_stream.CanRead;
73 public override bool CanWrite {
75 return m_stream.CanWrite;
79 public override bool CanSeek {
81 return m_stream.CanSeek;
85 public override long Length {
88 return m_stream.Length;
92 public override long Position {
94 CheckObjectDisposedException ();
95 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
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);
107 m_stream.Position = value;
112 protected override void Dispose (bool disposing)
116 if (m_buffer != null)
124 public override void Flush ()
126 CheckObjectDisposedException ();
128 if (m_buffer_reading) {
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;
139 public override long Seek (long offset, SeekOrigin origin)
141 CheckObjectDisposedException ();
143 throw new NotSupportedException (
144 Locale.GetText ("Non seekable stream."));
147 return m_stream.Seek (offset, origin);
150 public override void SetLength (long value)
152 CheckObjectDisposedException ();
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)
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) {
179 m_buffer_reading = true;
182 if (1 <= m_buffer_read_ahead - m_buffer_pos) {
183 return m_buffer [m_buffer_pos++];
187 if (m_buffer_pos >= m_buffer_read_ahead) {
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++];
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) {
211 m_buffer_reading = false;
214 // reordered to avoid possible integer overflow
215 if (m_buffer_pos >= m_buffer.Length - 1) {
219 m_buffer [m_buffer_pos++] = value;
222 public override int Read ([In,Out] byte[] array, int offset, int count)
225 throw new ArgumentNullException ("array");
226 CheckObjectDisposedException ();
227 if (!m_stream.CanRead) {
228 throw new NotSupportedException (
229 Locale.GetText ("Cannot read from stream"));
232 throw new ArgumentOutOfRangeException ("offset", "< 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) {
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) {
250 m_buffer_read_ahead = 0;
256 int ret = m_buffer_read_ahead - m_buffer_pos;
257 Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, ret);
259 m_buffer_read_ahead = 0;
263 if (count >= m_buffer.Length) {
264 ret += m_stream.Read (array, offset, count);
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;
273 Buffer.BlockCopyInternal (m_buffer, 0, array, offset, m_buffer_read_ahead);
274 ret += m_buffer_read_ahead;
275 m_buffer_read_ahead = 0;
282 public override void Write (byte[] array, int offset, int count)
285 throw new ArgumentNullException ("array");
286 CheckObjectDisposedException ();
287 if (!m_stream.CanWrite) {
288 throw new NotSupportedException (
289 Locale.GetText ("Cannot write to stream"));
292 throw new ArgumentOutOfRangeException ("offset", "< 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) {
301 m_buffer_reading = false;
304 // reordered to avoid possible integer overflow
305 if (m_buffer_pos >= m_buffer.Length - count) {
307 m_stream.Write (array, offset, count);
310 Buffer.BlockCopyInternal (array, offset, m_buffer, m_buffer_pos, count);
311 m_buffer_pos += count;
315 private void CheckObjectDisposedException ()
318 throw new ObjectDisposedException ("BufferedStream",
319 Locale.GetText ("Stream is closed"));