2 // System.IO.BinaryReader
5 // Matt Kimball (matt@kimball.net)
6 // Dick Porter (dick@ximian.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Globalization
;
37 public class BinaryReader
: IDisposable
{
40 int m_encoding_max_byte
;
44 private bool m_disposed
= false;
46 public BinaryReader(Stream input
) : this(input
, Encoding
.UTF8Unmarked
) {
49 public BinaryReader(Stream input
, Encoding encoding
) {
50 if (input
== null || encoding
== null)
51 throw new ArgumentNullException(Locale
.GetText ("Input or Encoding is a null reference."));
53 throw new ArgumentException(Locale
.GetText ("The stream doesn't support reading."));
56 m_encoding
= encoding
;
57 m_encoding_max_byte
= m_encoding
.GetMaxByteCount(1);
58 m_buffer
= new byte [32];
61 public virtual Stream BaseStream
{
67 public virtual void Close() {
72 protected virtual void Dispose (bool disposing
)
74 if (disposing
&& m_stream
!= null)
83 void IDisposable
.Dispose()
88 protected virtual void FillBuffer (int bytes
)
91 throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
93 throw new IOException("Stream is invalid");
97 /* Cope with partial reads */
101 int n
=m_stream
.Read(m_buffer
, pos
, bytes
-pos
);
103 throw new EndOfStreamException();
110 public virtual int PeekChar() {
114 throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
116 throw new IOException("Stream is invalid");
119 if ( !m_stream
.CanSeek
)
124 char[] result
= new char[1];
128 int ccount
= ReadCharBytes (result
, 0, 1, out bytes
, out bcount
);
130 // Reposition the stream
131 m_stream
.Position
-= bcount
;
133 // If we read 0 characters then return -1
139 // Return the single character we read
143 public virtual int Read() {
144 char[] decode
= new char[1];
146 int count
=Read(decode
, 0, 1);
148 /* No chars available */
155 public virtual int Read(byte[] buffer
, int index
, int count
) {
159 throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
161 throw new IOException("Stream is invalid");
164 if (buffer
== null) {
165 throw new ArgumentNullException("buffer is null");
168 throw new ArgumentOutOfRangeException("index is less than 0");
171 throw new ArgumentOutOfRangeException("count is less than 0");
173 if (buffer
.Length
- index
< count
) {
174 throw new ArgumentException("buffer is too small");
177 int bytes_read
=m_stream
.Read(buffer
, index
, count
);
182 public virtual int Read(char[] buffer
, int index
, int count
) {
187 throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
189 throw new IOException("Stream is invalid");
192 if (buffer
== null) {
193 throw new ArgumentNullException("buffer is null");
196 throw new ArgumentOutOfRangeException("index is less than 0");
199 throw new ArgumentOutOfRangeException("count is less than 0");
201 if (buffer
.Length
- index
< count
) {
202 throw new ArgumentException("buffer is too small");
207 return ReadCharBytes (buffer
, index
, count
, out bytes
, out bytes_read
);
210 private int ReadCharBytes(char[] buffer
, int index
, int count
, out byte[] bytes
, out int bytes_read
)
215 while(chars_read
< count
)
217 CheckBuffer(bytes_read
+ 1);
219 int read_byte
= m_stream
.ReadByte();
228 m_buffer
[bytes_read
]=(byte)read_byte
;
231 chars_read
=m_encoding
.GetChars(m_buffer
, 0,
241 protected int Read7BitEncodedInt() {
249 ret
= ret
| ((b
& 0x7f) << shift
);
251 } while ((b
& 0x80) == 0x80);
256 public virtual bool ReadBoolean() {
258 // true if the byte is non-zero; otherwise false.
259 return ReadByte() != 0;
262 public virtual byte ReadByte() {
263 int val
= m_stream
.ReadByte ();
267 throw new EndOfStreamException ();
270 public virtual byte[] ReadBytes(int count
) {
274 throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
276 throw new IOException("Stream is invalid");
280 throw new ArgumentOutOfRangeException("count is less than 0");
283 /* Can't use FillBuffer() here, because it's OK to
284 * return fewer bytes than were requested
287 byte[] buf
= new byte[count
];
292 int n
=m_stream
.Read(buf
, pos
, count
-pos
);
302 byte[] new_buffer
=new byte[pos
];
303 Array
.Copy(buf
, new_buffer
, pos
);
310 public virtual char ReadChar() {
314 throw new EndOfStreamException();
320 public virtual char[] ReadChars(int count
) {
322 throw new ArgumentOutOfRangeException("count is less than 0");
325 char[] full
= new char[count
];
326 int chars
= Read(full
, 0, count
);
329 throw new EndOfStreamException();
330 } else if (chars
!= full
.Length
) {
331 char[] ret
= new char[chars
];
332 Array
.Copy(full
, 0, ret
, 0, chars
);
339 unsafe public virtual decimal ReadDecimal() {
343 byte* ret_ptr
= (byte *)&ret
;
344 for (int i
= 0; i
< 16; i
++) {
347 * internal representation of decimal is
348 * ss32, hi32, lo32, mi32,
349 * but in stream it is
350 * lo32, mi32, hi32, ss32
351 * So we have to rerange this int32 values
356 ret_ptr
[i
+ 8] = m_buffer
[i
];
359 ret_ptr
[i
+ 8] = m_buffer
[i
];
362 ret_ptr
[i
- 4] = m_buffer
[i
];
365 ret_ptr
[i
- 12] = m_buffer
[i
];
372 public virtual double ReadDouble() {
375 return(BitConverter
.ToDouble(m_buffer
, 0));
378 public virtual short ReadInt16() {
381 return((short) (m_buffer
[0] | (m_buffer
[1] << 8)));
384 public virtual int ReadInt32() {
387 return(m_buffer
[0] | (m_buffer
[1] << 8) |
388 (m_buffer
[2] << 16) | (m_buffer
[3] << 24));
391 public virtual long ReadInt64() {
394 uint ret_low
= (uint) (m_buffer
[0] |
396 (m_buffer
[2] << 16) |
399 uint ret_high
= (uint) (m_buffer
[4] |
401 (m_buffer
[6] << 16) |
404 return (long) ((((ulong) ret_high
) << 32) | ret_low
);
407 [CLSCompliant(false)]
408 public virtual sbyte ReadSByte() {
409 return (sbyte) ReadByte ();
412 public virtual string ReadString() {
413 /* Inspection of BinaryWriter-written files
414 * shows that the length is given in bytes,
417 int len
= Read7BitEncodedInt();
421 char[] str
= m_encoding
.GetChars(m_buffer
, 0, len
);
423 return(new String(str
));
426 public virtual float ReadSingle() {
429 return(BitConverter
.ToSingle(m_buffer
, 0));
432 [CLSCompliant(false)]
433 public virtual ushort ReadUInt16() {
436 return((ushort) (m_buffer
[0] | (m_buffer
[1] << 8)));
439 [CLSCompliant(false)]
440 public virtual uint ReadUInt32() {
444 return((uint) (m_buffer
[0] |
446 (m_buffer
[2] << 16) |
447 (m_buffer
[3] << 24)));
450 [CLSCompliant(false)]
451 public virtual ulong ReadUInt64() {
454 uint ret_low
= (uint) (m_buffer
[0] |
456 (m_buffer
[2] << 16) |
459 uint ret_high
= (uint) (m_buffer
[4] |
461 (m_buffer
[6] << 16) |
464 return (((ulong) ret_high
) << 32) | ret_low
;
467 /* Ensures that m_buffer is at least length bytes
468 * long, growing it if necessary
470 private void CheckBuffer(int length
)
472 if(m_buffer
.Length
<= length
) {
473 byte[] new_buffer
=new byte[length
];
474 Array
.Copy(m_buffer
, new_buffer
,