* BufferedStream.cs, FileStream.cs, MemoryStream.cs, Stream.cs:
[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 using System.Runtime.InteropServices;
10
11 namespace System.IO {
12         public sealed class BufferedStream : Stream {
13                 Stream m_stream;
14                 byte[] m_buffer;
15                 int m_buffer_pos;
16                 int m_buffer_read_ahead;
17                 bool m_buffer_reading;
18                 private bool disposed = false;
19
20                 public BufferedStream(Stream stream) : this(stream, 4096) {
21                 }
22
23                 public BufferedStream(Stream stream, int buffer_size) {
24
25                         if (stream == null)
26                                 throw new ArgumentNullException ("stream was null");
27                         if (buffer_size < 0)
28                                 throw new ArgumentOutOfRangeException ();
29                                                 
30                         m_stream = stream;
31                         m_buffer = new byte[buffer_size];
32                 }
33
34                 public override bool CanRead {
35                         get {
36                                 return m_stream.CanRead;
37                         }
38                 }
39
40                 public override bool CanWrite {
41                         get {
42                                 return m_stream.CanWrite;
43                         }
44                 }
45
46                 public override bool CanSeek {
47                         get {
48                                 return m_stream.CanSeek;
49                         }
50                 }
51
52                 public override long Length {
53                         get {                           
54                                 Flush ();
55                                 return m_stream.Length;
56                         }
57                 }
58                 
59                 public override long Position {
60                         get {
61                                 CheckObjectDisposedException ();
62                                 return m_stream.Position - m_buffer_read_ahead + m_buffer_pos;
63                         }
64
65                         set {
66                                 Flush();
67                                 m_stream.Position = value;
68                         }
69                 }
70
71                 public override void Close() {
72                         
73                         if (m_buffer != null)
74                                 Flush();
75
76                         m_stream.Close();
77                         m_buffer = null;
78                         disposed = true;
79                 }
80
81                 public override void Flush() {
82                         
83                         CheckObjectDisposedException ();
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([In,Out] 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 }