2002-08-09 Nick Drochak <ndrochak@gol.com>
[mono.git] / mcs / class / corlib / System.IO / BinaryReader.cs
1 //
2 // System.IO.BinaryReader
3 //
4 // Author:
5 //   Matt Kimball (matt@kimball.net)
6 //
7
8 using System;
9 using System.Text;
10 using System.Globalization;
11
12 namespace System.IO {
13         public class BinaryReader : IDisposable {
14                 Stream m_stream;
15                 Encoding m_encoding;
16                 int m_encoding_max_byte;
17
18                 byte[] m_buffer;
19                 int m_buffer_used;
20                 int m_buffer_pos;
21
22
23                 public BinaryReader(Stream input) : this(input, Encoding.UTF8) {
24                 }
25
26                 public BinaryReader(Stream input, Encoding encoding) {
27                         if (input == null || encoding == null) 
28                                 throw new ArgumentNullException(Locale.GetText ("Input or Encoding is a null reference."));
29                         if (!input.CanRead)
30                                 throw new ArgumentException(Locale.GetText ("The stream doesn't support reading."));
31
32                         m_stream = input;
33                         m_encoding = encoding;
34                         m_encoding_max_byte = m_encoding.GetMaxByteCount(1);
35                         m_buffer = new byte [32];
36                 }
37
38                 public virtual Stream BaseStream {
39                         get {
40                                 return m_stream;
41                         }
42                 }
43
44                 public virtual void Close() {
45                         Dispose (true);
46                         m_stream.Close();
47                 }
48                 
49                 protected virtual void Dispose (bool disposing)
50                 {
51                         if (disposing)
52                                 m_stream.Close ();
53
54                         m_buffer = null;
55                         m_buffer_used = 0;
56                 }
57
58                 void IDisposable.Dispose() 
59                 {
60                         Dispose (true);
61                 }
62
63                 protected virtual void FillBuffer(int bytes) {
64                         if (!EnsureBuffered(m_buffer_used - m_buffer_pos + bytes)) {
65                                 throw new EndOfStreamException();
66                         }
67                 }
68
69                 public virtual int PeekChar() {
70                         EnsureBuffered(m_encoding_max_byte);
71                         
72                         int i;
73                         for (i = 1; m_encoding.GetCharCount(m_buffer, m_buffer_pos, i) == 0; i++) {
74                                 if (m_buffer_pos + i >= m_buffer_used) {
75                                         return -1;
76                                 }
77                         }
78
79                         char[] decode = m_encoding.GetChars(m_buffer, m_buffer_pos, i);
80                         return decode[0];
81                 }
82
83                 public virtual int Read() {
84                         char[] decode = new char[1];
85
86                         Read(decode, 0, 1);
87                         return decode[0];
88                 }
89
90                 public virtual int Read(byte[] buffer, int index, int count) {
91                         if (buffer == null) {
92                                 throw new ArgumentNullException();
93                         }
94                         if (buffer.Length - index < count) {
95                                 throw new ArgumentException();
96                         }
97                         if (index < 0 || count < 0) {
98                                 throw new ArgumentOutOfRangeException();
99                         }
100
101                         EnsureBuffered(count);
102                         
103                         if (m_buffer_used - m_buffer_pos < count) {
104                                 count = m_buffer_used - m_buffer_pos;
105                         }
106
107                         Array.Copy(m_buffer, m_buffer_pos, buffer, index, count);
108
109                         ConsumeBuffered(count);
110                         return count;
111                 }
112
113                 public virtual int Read(char[] buffer, int index, int count) {
114                         if (buffer == null) {
115                                 throw new ArgumentNullException();
116                         }
117                         if (buffer.Length - index < count) {
118                                 throw new ArgumentException();
119                         }
120                         if (index < 0 || count < 0) {
121                                 throw new ArgumentOutOfRangeException();
122                         }
123
124                         EnsureBuffered(m_encoding_max_byte * count);
125
126                         int i;          
127                         for (i = 1; m_encoding.GetCharCount(m_buffer, m_buffer_pos, i) < count; i++) {
128                                 if (m_buffer_pos + i >= m_buffer_used) {
129                                         break;
130                                 }
131                         }
132                         
133                         count = m_encoding.GetCharCount(m_buffer, m_buffer_pos, i);
134
135                         char[] dec = m_encoding.GetChars(m_buffer, m_buffer_pos, i);
136                         Array.Copy(dec, 0, buffer, index, count);
137
138                         ConsumeBuffered(i);
139                         return count;
140                 }
141
142                 protected int Read7BitEncodedInt() {
143                         int ret = 0;
144                         int shift = 0;
145                         int count = 0;
146                         byte b;
147
148                         do {
149                                 if (!EnsureBuffered(++count)) {
150                                         throw new EndOfStreamException();
151                                 }
152                                 b = m_buffer[m_buffer_pos + count - 1];
153                                 
154                                 ret = ret | ((b & 0x7f) << shift);
155                                 shift += 7;
156                         } while ((b & 0x80) == 0x80);
157
158                         ConsumeBuffered(count);
159                         return ret;
160                 }
161
162                 public virtual bool ReadBoolean() {
163                         if (!EnsureBuffered(1)) {
164                                 throw new EndOfStreamException();
165                         }
166
167                         // Return value:
168                         //  true if the byte is non-zero; otherwise false.
169                         bool ret = (m_buffer[m_buffer_pos] != 0);
170                         ConsumeBuffered(1);
171                         return ret;
172                 }
173
174                 public virtual byte ReadByte() {
175                         if (!EnsureBuffered(1)) {
176                                 throw new EndOfStreamException();
177                         }
178
179                         byte ret = m_buffer[m_buffer_pos];
180                         ConsumeBuffered(1);
181                         return ret;
182                 }
183
184                 public virtual byte[] ReadBytes(int count) {
185                         if (count < 0) {
186                                 throw new ArgumentOutOfRangeException();
187                         }
188
189                         EnsureBuffered(count);
190
191                         if (count > m_buffer_used - m_buffer_pos) {
192                                 count = m_buffer_used - m_buffer_pos;
193                         }
194
195                         if (count == 0) {
196                                 throw new EndOfStreamException();
197                         }
198
199                         byte[] buf = new byte[count];
200                         Read(buf, 0, count);
201                         return buf;
202                 }
203
204                 public virtual char ReadChar() {
205                         char[] buf = ReadChars(1);
206                         return buf[0];
207                 }
208
209                 public virtual char[] ReadChars(int count) {
210                         if (count < 0) {
211                                 throw new ArgumentOutOfRangeException();
212                         }
213
214                         char[] full = new char[count];
215                         count = Read(full, 0, count);
216                         
217                         if (count != full.Length) {
218                                 char[] ret = new char[count];
219                                 Array.Copy(full, 0, ret, 0, count);
220                                 return ret;
221                         } else {
222                                 return full;
223                         }
224                 }
225
226                 unsafe public virtual decimal ReadDecimal() {
227                         if (!EnsureBuffered(16)) {
228                                 throw new EndOfStreamException();
229                         }
230
231                         decimal ret;
232                         byte* ret_ptr = (byte *)&ret;
233                         for (int i = 0; i < 16; i++) {
234                                 ret_ptr[i] = m_buffer[m_buffer_pos + i];
235                         }
236
237                         ConsumeBuffered(16);
238                         return ret;
239                 }
240
241                 public virtual double ReadDouble() {
242                         if (!EnsureBuffered(8)) {
243                                 throw new EndOfStreamException();
244                         }
245
246                         double ret = BitConverter.ToDouble(m_buffer, m_buffer_pos);
247                         ConsumeBuffered(8);
248                         return ret;
249                 }
250
251                 public virtual short ReadInt16() {
252                         if (!EnsureBuffered(2)) {
253                                 throw new EndOfStreamException();
254                         }
255
256                         short ret = (short) (m_buffer[m_buffer_pos] | (m_buffer[m_buffer_pos + 1] << 8));
257                         ConsumeBuffered(2);
258                         return ret;
259                 }
260
261                 public virtual int ReadInt32() {
262                         if (!EnsureBuffered(4)) {
263                                 throw new EndOfStreamException();
264                         }
265
266                         int ret = (m_buffer[m_buffer_pos]             |
267                                    (m_buffer[m_buffer_pos + 1] << 8)  |
268                                    (m_buffer[m_buffer_pos + 2] << 16) |
269                                    (m_buffer[m_buffer_pos + 3] << 24)
270                                   );
271                         ConsumeBuffered(4);
272                         return ret;
273                 }
274
275                 public virtual long ReadInt64() {
276                         if (!EnsureBuffered(8)) {
277                                 throw new EndOfStreamException();
278                         }
279
280                         uint ret_low  = (uint) (m_buffer[m_buffer_pos]            |
281                                                (m_buffer[m_buffer_pos + 1] << 8)  |
282                                                (m_buffer[m_buffer_pos + 2] << 16) |
283                                                (m_buffer[m_buffer_pos + 3] << 24)
284                                                );
285                         uint ret_high = (uint) (m_buffer[m_buffer_pos + 4]        |
286                                                (m_buffer[m_buffer_pos + 5] << 8)  |
287                                                (m_buffer[m_buffer_pos + 6] << 16) |
288                                                (m_buffer[m_buffer_pos + 7] << 24)
289                                                );
290                         ConsumeBuffered(8);
291                         return (long) ((((ulong) ret_high) << 32) | ret_low);
292                 }
293
294                 [CLSCompliant(false)]
295                 unsafe public virtual sbyte ReadSByte() {
296                         if (!EnsureBuffered(1)) {
297                                 throw new EndOfStreamException();
298                         }
299
300                         sbyte ret;
301                         byte* ret_ptr = (byte *)&ret;
302                         ret_ptr[0] = m_buffer[m_buffer_pos];
303
304                         ConsumeBuffered(1);
305                         return ret;
306                 }
307
308                 public virtual string ReadString() {
309                         int len = Read7BitEncodedInt();
310
311                         char[] str = ReadChars(len);
312                         string ret = "";
313                         for (int i = 0; i < str.Length; i++) {
314                                 ret = ret + str[i];
315                         }
316
317                         return ret;
318                 }
319
320                 public virtual float ReadSingle() {
321                         if (!EnsureBuffered(4)) {
322                                 throw new EndOfStreamException();
323                         }
324
325                         float ret = BitConverter.ToSingle(m_buffer, m_buffer_pos);
326                         ConsumeBuffered(4);
327                         return ret;
328                 }
329
330                 [CLSCompliant(false)]
331                 public virtual ushort ReadUInt16() {
332                         if (!EnsureBuffered(2)) {
333                                 throw new EndOfStreamException();
334                         }
335
336                         ushort ret = (ushort) (m_buffer[m_buffer_pos] | (m_buffer[m_buffer_pos + 1] << 8));
337                         ConsumeBuffered(2);
338                         return ret;
339                 }
340
341                 [CLSCompliant(false)]
342                 public virtual uint ReadUInt32() {
343                         if (!EnsureBuffered(4)) {
344                                 throw new EndOfStreamException();
345                         }
346
347                         uint ret = (uint) (m_buffer[m_buffer_pos]            |
348                                           (m_buffer[m_buffer_pos + 1] << 8)  |
349                                           (m_buffer[m_buffer_pos + 2] << 16) |
350                                           (m_buffer[m_buffer_pos + 3] << 24)
351                                           );
352                         ConsumeBuffered(4);
353                         return ret;
354                 }
355
356                 [CLSCompliant(false)]
357                 public virtual ulong ReadUInt64() {
358                         if (!EnsureBuffered(8)) {
359                                 throw new EndOfStreamException();
360                         }
361
362                         uint ret_low  = (uint) (m_buffer[m_buffer_pos]            |
363                                                (m_buffer[m_buffer_pos + 1] << 8)  |
364                                                (m_buffer[m_buffer_pos + 2] << 16) |
365                                                (m_buffer[m_buffer_pos + 3] << 24)
366                                                );
367                         uint ret_high = (uint) (m_buffer[m_buffer_pos + 4]        |
368                                                (m_buffer[m_buffer_pos + 5] << 8)  |
369                                                (m_buffer[m_buffer_pos + 6] << 16) |
370                                                (m_buffer[m_buffer_pos + 7] << 24)
371                                                );
372                         ConsumeBuffered(8);
373                         return (((ulong) ret_high) << 32) | ret_low;
374                 }
375
376                 
377                 bool EnsureBuffered(int bytes) {
378                         int needed = bytes - (m_buffer_used - m_buffer_pos);
379                         if (needed < 0)
380                                 return true;
381
382                         if (m_buffer_used + needed > m_buffer.Length) {
383                                 byte[] old_buffer = m_buffer;
384                                 m_buffer = new byte[m_buffer_used + needed];
385                                 Array.Copy(old_buffer, 0, m_buffer, 0, m_buffer_used);
386                                 m_buffer_pos = m_buffer_used;
387                         }
388
389                         int n = m_stream.Read(m_buffer, m_buffer_used, needed);
390                         if (n == 0) return false;
391
392                         m_buffer_used += n;
393
394                         return (m_buffer_used >= m_buffer_pos + bytes);
395                 }
396
397
398                 void ConsumeBuffered(int bytes) {
399                         m_buffer_pos += bytes;
400                 }
401         }
402 }