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;
38 public sealed class BufferedStream : Stream {
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)
53 throw new ArgumentNullException ("stream");
54 // LAMESPEC: documented as < 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."));
63 m_buffer = new byte [buffer_size];
66 public override bool CanRead {
68 return m_stream.CanRead;
72 public override bool CanWrite {
74 return m_stream.CanWrite;
78 public override bool CanSeek {
80 return m_stream.CanSeek;
84 public override long Length {
87 return m_stream.Length;
91 public override long Position {
93 CheckObjectDisposedException ();
94 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
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);
106 m_stream.Position = value;
111 public override void Close ()
113 if (m_buffer != null)
121 public override void Flush ()
123 CheckObjectDisposedException ();
125 if (m_buffer_reading) {
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;
136 public override long Seek (long offset, SeekOrigin origin)
138 CheckObjectDisposedException ();
140 throw new NotSupportedException (
141 Locale.GetText ("Non seekable stream."));
144 return m_stream.Seek (offset, origin);
147 public override void SetLength (long value)
149 CheckObjectDisposedException ();
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)
165 public override int ReadByte ()
167 CheckObjectDisposedException ();
169 byte[] b = new byte[1];
171 if (Read(b, 0, 1) == 1) {
178 public override void WriteByte (byte value)
180 CheckObjectDisposedException ();
181 byte[] b = new byte[1];
187 public override int Read ([In,Out] byte[] array, int offset, int count)
190 throw new ArgumentNullException ("array");
191 CheckObjectDisposedException ();
192 if (!m_stream.CanRead) {
193 throw new NotSupportedException (
194 Locale.GetText ("Cannot read from stream"));
197 throw new ArgumentOutOfRangeException ("offset", "< 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) {
206 m_buffer_reading = true;
209 if (count <= m_buffer_read_ahead - m_buffer_pos) {
210 Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, count);
212 m_buffer_pos += count;
213 if (m_buffer_pos == m_buffer_read_ahead) {
215 m_buffer_read_ahead = 0;
221 int ret = m_buffer_read_ahead - m_buffer_pos;
222 Buffer.BlockCopyInternal (m_buffer, m_buffer_pos, array, offset, ret);
224 m_buffer_read_ahead = 0;
228 if (count >= m_buffer.Length) {
229 ret += m_stream.Read(array, offset, count);
231 m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
233 if (count < m_buffer_read_ahead) {
234 Buffer.BlockCopyInternal (m_buffer, 0, array, offset, count);
235 m_buffer_pos = count;
238 Buffer.BlockCopyInternal (m_buffer, 0, array, offset, m_buffer_read_ahead);
239 ret += m_buffer_read_ahead;
240 m_buffer_read_ahead = 0;
247 public override void Write (byte[] array, int offset, int count)
250 throw new ArgumentNullException ("array");
251 CheckObjectDisposedException ();
252 if (!m_stream.CanWrite) {
253 throw new NotSupportedException (
254 Locale.GetText ("Cannot write to stream"));
257 throw new ArgumentOutOfRangeException ("offset", "< 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) {
266 m_buffer_reading = false;
269 // reordered to avoid possible integer overflow
270 if (m_buffer_pos >= m_buffer.Length - count) {
272 m_stream.Write (array, offset, count);
275 Buffer.BlockCopyInternal (array, offset, m_buffer, m_buffer_pos, count);
276 m_buffer_pos += count;
280 private void CheckObjectDisposedException ()
283 throw new ObjectDisposedException ("BufferedStream",
284 Locale.GetText ("Stream is closed"));