// Author:
// Matt Kimball (matt@kimball.net)
// Dick Porter (dick@ximian.com)
+// Marek Safar (marek.safar@gmail.com)
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright 2011 Xamarin Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Text;
using System.Globalization;
using Mono.Security;
-#if NET_2_0
using System.Runtime.InteropServices;
-#endif
namespace System.IO {
-#if NET_2_0
[ComVisible (true)]
-#endif
public class BinaryReader : IDisposable {
Stream m_stream;
Encoding m_encoding;
- int m_encoding_max_byte;
byte[] m_buffer;
Decoder decoder;
- char [] charBuffer;
+ char[] charBuffer;
+ byte[] charByteBuffer;
//
// 128 chars should cover most strings in one grab.
const int MaxBufferSize = 128;
- private bool m_disposed = false;
-
- public BinaryReader(Stream input) : this(input, Encoding.UTF8UnmarkedUnsafe) {
+ private bool m_disposed;
+
+ public BinaryReader(Stream input)
+ : this(input, Encoding.UTF8UnmarkedUnsafe)
+ {
}
-
- public BinaryReader(Stream input, Encoding encoding) {
+
+#if NET_4_5
+ readonly bool leave_open;
+
+ public BinaryReader(Stream input, Encoding encoding)
+ : this (input, encoding, false)
+ {
+ }
+
+ public BinaryReader(Stream input, Encoding encoding, bool leaveOpen)
+#else
+ const bool leave_open = false;
+
+ public BinaryReader(Stream input, Encoding encoding)
+#endif
+ {
if (input == null || encoding == null)
throw new ArgumentNullException(Locale.GetText ("Input or Encoding is a null reference."));
if (!input.CanRead)
m_stream = input;
m_encoding = encoding;
+#if NET_4_5
+ leave_open = leaveOpen;
+#endif
decoder = encoding.GetDecoder ();
- m_buffer = new byte [32];
+
+ // internal buffer size is documented to be between 16 and the value
+ // returned by GetMaxByteCount for the specified encoding
+ m_buffer = new byte [Math.Max (16, encoding.GetMaxByteCount (1))];
}
public virtual Stream BaseStream {
protected virtual void Dispose (bool disposing)
{
- if (disposing && m_stream != null)
+ if (disposing && m_stream != null && !leave_open)
m_stream.Close ();
m_disposed = true;
charBuffer = null;
}
+#if NET_4_0
+ public void Dispose ()
+#else
void IDisposable.Dispose()
+#endif
{
Dispose (true);
}
- protected virtual void FillBuffer (int bytes)
+ protected virtual void FillBuffer (int numBytes)
{
+ if (numBytes > m_buffer.Length)
+ throw new ArgumentOutOfRangeException ("numBytes");
if (m_disposed)
throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
if (m_stream==null)
throw new IOException("Stream is invalid");
- CheckBuffer(bytes);
-
/* Cope with partial reads */
int pos=0;
- while(pos<bytes) {
- int n=m_stream.Read(m_buffer, pos, bytes-pos);
+ while(pos<numBytes) {
+ int n=m_stream.Read(m_buffer, pos, numBytes-pos);
if(n==0) {
throw new EndOfStreamException();
}
}
char[] result = new char[1];
- byte[] bytes;
int bcount;
- int ccount = ReadCharBytes (result, 0, 1, out bytes, out bcount);
+ int ccount = ReadCharBytes (result, 0, 1, out bcount);
// Reposition the stream
m_stream.Position -= bcount;
}
int bytes_read;
- byte[] bytes;
- return ReadCharBytes (buffer, index, count, out bytes, out bytes_read);
+ return ReadCharBytes (buffer, index, count, out bytes_read);
}
- private int ReadCharBytes(char[] buffer, int index, int count, out byte[] bytes, out int bytes_read)
+ private int ReadCharBytes (char[] buffer, int index, int count, out int bytes_read)
{
- int chars_read=0;
- bytes_read=0;
+ int chars_read = 0;
+ bytes_read = 0;
- while(chars_read < count)
- {
- CheckBuffer(bytes_read + 1);
+ while (chars_read < count) {
+ int pos = 0;
+ while (true) {
+ CheckBuffer (pos + 1);
- int read_byte = m_stream.ReadByte();
+ int read_byte = m_stream.ReadByte ();
- if(read_byte==-1)
- {
- /* EOF */
- bytes = m_buffer;
- return(chars_read);
- }
+ if (read_byte == -1)
+ /* EOF */
+ return chars_read;
- m_buffer[bytes_read]=(byte)read_byte;
- bytes_read++;
+ m_buffer [pos ++] = (byte)read_byte;
+ bytes_read ++;
- chars_read=m_encoding.GetChars(m_buffer, 0,
- bytes_read,
- buffer, index);
-
+ int n = m_encoding.GetChars (m_buffer, 0, pos, buffer, index + chars_read);
+ if (n > 0)
+ break;
+ }
+ chars_read ++;
}
- bytes = m_buffer;
- return(chars_read);
+ return chars_read;
}
protected int Read7BitEncodedInt() {
int ret = 0;
int shift = 0;
+ int len;
byte b;
- do {
+ for (len = 0; len < 5; ++len) {
b = ReadByte();
ret = ret | ((b & 0x7f) << shift);
shift += 7;
- } while ((b & 0x80) == 0x80);
+ if ((b & 0x80) == 0)
+ break;
+ }
- return ret;
+ if (len < 5)
+ return ret;
+ else
+ throw new FormatException ("Too many bytes in what should have been a 7 bit encoded Int32.");
}
public virtual bool ReadBoolean() {
return((char)ch);
}
- public virtual char[] ReadChars(int count) {
+ public virtual char[] ReadChars (int count)
+ {
if (count < 0) {
throw new ArgumentOutOfRangeException("count is less than 0");
}
+ if (m_stream == null) {
+ if (m_disposed)
+ throw new ObjectDisposedException ("BinaryReader", "Cannot read from a closed BinaryReader.");
+
+ throw new IOException("Stream is invalid");
+ }
+
if (count == 0)
- return new char [0];
+ return EmptyArray<char>.Value;
char[] full = new char[count];
- int chars = Read(full, 0, count);
+ int bytes_read;
+ int chars = ReadCharBytes (full, 0, count, out bytes_read);
- if (chars == 0) {
+ if (chars == 0)
throw new EndOfStreamException();
- } else if (chars != full.Length) {
- char[] ret = new char[chars];
- Array.Copy(full, 0, ret, 0, chars);
- return ret;
- } else {
- return full;
+
+ if (chars != count) {
+ var new_buffer = new char[chars];
+ Buffer.BlockCopyInternal (full, 0, new_buffer, 0, 2 * chars);
+ return new_buffer;
}
+
+ return full;
}
unsafe public virtual decimal ReadDecimal() {
if (len == 0)
return String.Empty;
-
- if (charBuffer == null)
- charBuffer = new char [MaxBufferSize];
+ if (charByteBuffer == null) {
+ charBuffer = new char [m_encoding.GetMaxByteCount (MaxBufferSize)];
+ charByteBuffer = new byte [MaxBufferSize];
+ }
//
// We read the string here in small chunks. Also, we
//
StringBuilder sb = null;
do {
- int readLen = (len > MaxBufferSize)
- ? MaxBufferSize
- : len;
+ int readLen = Math.Min (MaxBufferSize, len);
- FillBuffer (readLen);
+ readLen = m_stream.Read (charByteBuffer, 0, readLen);
+ if (readLen == 0)
+ throw new EndOfStreamException();
- int cch = decoder.GetChars (m_buffer, 0, readLen, charBuffer, 0);
+ int cch = decoder.GetChars (charByteBuffer, 0, readLen, charBuffer, 0);
if (sb == null && readLen == len) // ok, we got out the easy way, dont bother with the sb
return new String (charBuffer, 0, cch);