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"));