2003-04-24 Pedro Martnez Juli <yoros@wanadoo.es>
[mono.git] / mcs / class / corlib / System.IO / BufferedStream.cs
1 //
2 // System.IO.BufferedStream
3 //
4 // Author:
5 //   Matt Kimball (matt@kimball.net)
6 //   Ville Palo <vi64pa@kolumbus.fi>
7 //
8
9
10 namespace System.IO {
11         public sealed class BufferedStream : Stream {
12                 Stream m_stream;
13                 byte[] m_buffer;
14                 int m_buffer_pos;
15                 int m_buffer_read_ahead;
16                 bool m_buffer_reading;
17                 private bool disposed = false;
18
19                 public BufferedStream(Stream stream) : this(stream, 4096) {
20                 }
21
22                 public BufferedStream(Stream stream, int buffer_size) {
23
24                         if (stream == null)
25                                 throw new ArgumentNullException ("stream was null");
26                         if (buffer_size < 0)
27                                 throw new ArgumentOutOfRangeException ();
28                         
29                         // There are stream classes that don't support Positioning.
30                         if (stream.CanSeek) {
31                                 // if stream is closed this throws an exception
32                                 // FIXME: better way?
33                                 long l = stream.Position;
34                         }
35                         
36                         m_stream = stream;
37                         m_buffer = new byte[buffer_size];
38                 }
39
40                 public override bool CanRead {
41                         get {
42                                 return m_stream.CanRead;
43                         }
44                 }
45
46                 public override bool CanWrite {
47                         get {
48                                 return m_stream.CanWrite;
49                         }
50                 }
51
52                 public override bool CanSeek {
53                         get {
54                                 return m_stream.CanSeek;
55                         }
56                 }
57
58                 public override long Length {
59                         get {                           
60                                 Flush ();
61                                 return m_stream.Length;
62                         }
63                 }
64                 
65                 public override long Position {
66                         get {
67                                 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
68                         }
69
70                         set {
71                                 Flush();
72                                 m_stream.Position = value;
73                         }
74                 }
75
76                 public override void Close() {
77                         Flush();
78                         m_stream.Close();
79                         m_buffer = null;
80                         disposed = true;
81                 }
82
83                 public override void Flush() {
84                         
85                         if (m_buffer_reading) {
86                                 if (CanSeek)
87                                         m_stream.Position = Position;
88                         } else if (m_buffer_pos > 0) {
89                                 m_stream.Write(m_buffer, 0, m_buffer_pos);
90                         }
91
92                         m_buffer_read_ahead = 0;
93                         m_buffer_pos = 0;
94                 }
95
96                 public override long Seek(long offset, SeekOrigin origin) {
97                         Flush();
98                         return m_stream.Seek(offset, origin);
99                 }
100
101                 public override void SetLength(long value) {
102                         m_stream.SetLength(value);
103                 }
104
105                 public override int ReadByte() {
106
107                         CheckObjectDisposedException ();
108                         
109                         byte[] b = new byte[1];
110
111                         if (Read(b, 0, 1) == 1) {
112                                 return b[0];
113                         } else {
114                                 return -1;
115                         }
116                 }
117
118                 public override void WriteByte(byte value) {
119
120                         CheckObjectDisposedException ();
121                         byte[] b = new byte[1];
122
123                         b[0] = value;
124                         Write(b, 0, 1);
125                 }
126
127                 public override int Read(byte[] array, int offset, int count) {
128
129                         CheckObjectDisposedException ();
130
131                         if (array.Length < offset + count)
132                                 throw new ArgumentException ();
133                         if (offset < 0)
134                                 throw new ArgumentOutOfRangeException ("Offset was negative value.");
135
136                         if (!m_buffer_reading) {
137                                 Flush();
138                                 m_buffer_reading = true;
139                         }
140
141                         if (count <= m_buffer_read_ahead - m_buffer_pos) {
142                                 Array.Copy(m_buffer, m_buffer_pos, array, offset, count);
143
144                                 m_buffer_pos += count;
145                                 if (m_buffer_pos == m_buffer_read_ahead) {
146                                         m_buffer_pos = 0;
147                                         m_buffer_read_ahead = 0;
148                                 }
149
150                                 return count;
151                         }
152
153                         int ret = m_buffer_read_ahead - m_buffer_pos;
154                         Array.Copy(m_buffer, m_buffer_pos, array, offset, ret);
155                         m_buffer_pos = 0;
156                         m_buffer_read_ahead = 0;
157                         offset += ret;
158                         count -= ret;
159
160                         if (count >= m_buffer.Length) {
161                                 ret += m_stream.Read(array, offset, count);
162                         } else {
163                                 m_buffer_read_ahead = m_stream.Read(m_buffer, 0, m_buffer.Length);
164                                 
165                                 if (count < m_buffer_read_ahead) {
166                                         Array.Copy(m_buffer, 0, array, offset, count);
167                                         m_buffer_pos = count;
168                                         ret += count;
169                                 } else {
170                                         Array.Copy(m_buffer, 0, array, offset, m_buffer_read_ahead);
171                                         ret += m_buffer_read_ahead;
172                                         m_buffer_read_ahead = 0;
173                                 }
174                         }
175
176                         return ret;
177                 }
178
179                 public override void Write(byte[] array, int offset, int count) {
180
181                         CheckObjectDisposedException ();
182
183                         if (!m_stream.CanRead)
184                                 throw new NotSupportedException ();
185                         if (offset < 0)
186                                 throw new ArgumentOutOfRangeException ();
187
188                         if (m_buffer_reading) {
189                                 Flush();
190                                 m_buffer_reading = false;
191                         }
192
193                         if (m_buffer_pos + count >= m_buffer.Length) {
194                                 Flush();
195                                 m_stream.Write(array, offset, count);
196                         } else {
197                                 Array.Copy(array, offset, m_buffer, m_buffer_pos, count);
198                                 m_buffer_pos += count;
199                         }
200                 }
201
202                 private void CheckObjectDisposedException () 
203                 {
204                         if (disposed) 
205                                 throw new ObjectDisposedException ("BufferedStream", "Stream is closed");
206                 }                       
207         }
208 }