// 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;
+using System.Runtime.InteropServices;
namespace System.IO {
+ [ComVisible (true)]
public class BinaryReader : IDisposable {
Stream m_stream;
Encoding m_encoding;
- int m_encoding_max_byte;
byte[] m_buffer;
+
+ Decoder decoder;
+ char[] charBuffer;
+ byte[] charByteBuffer;
- private bool m_disposed = false;
+ //
+ // 128 chars should cover most strings in one grab.
+ //
+ const int MaxBufferSize = 128;
- public BinaryReader(Stream input) : this(input, Encoding.UTF8Unmarked) {
+
+ 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;
- m_encoding_max_byte = m_encoding.GetMaxByteCount(1);
- m_buffer = new byte [32];
+#if NET_4_5
+ leave_open = leaveOpen;
+#endif
+ decoder = encoding.GetDecoder ();
+
+ // 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;
m_buffer = null;
m_encoding = null;
m_stream = null;
+ charBuffer = null;
}
+#if NET_4_0 || NET_2_1
+ 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;
}
public virtual int Read() {
- char[] decode = new char[1];
+ if (charBuffer == null)
+ charBuffer = new char [MaxBufferSize];
- int count=Read(decode, 0, 1);
- if(count==0) {
+ int count = Read (charBuffer, 0, 1);
+ if(count == 0) {
/* No chars available */
- return(-1);
+ return -1;
}
- return decode[0];
+ return charBuffer [0];
}
public virtual int Read(byte[] buffer, int index, int count) {
}
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) \r
+ 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() {
byte[] buf = new byte[count];
int pos=0;
- while(pos < count) \r
+ while(pos < count)
{
int n=m_stream.Read(buf, pos, count-pos);
if(n==0) {
if (pos!=count) {
byte[] new_buffer=new byte[pos];
- Array.Copy(buf, new_buffer, pos);
+ Buffer.BlockCopyInternal (buf, 0, new_buffer, 0, pos);
return(new_buffer);
}
throw new ArgumentOutOfRangeException("count is less than 0");
}
+ if (count == 0)
+ return new char [0];
+
char[] full = new char[count];
int chars = Read(full, 0, count);
* not chars
*/
int len = Read7BitEncodedInt();
+
+ if (len < 0)
+ throw new IOException ("Invalid binary file (string len < 0)");
- FillBuffer(len);
+ if (len == 0)
+ return String.Empty;
- char[] str = m_encoding.GetChars(m_buffer, 0, len);
+ if (charByteBuffer == null) {
+ charBuffer = new char [m_encoding.GetMaxByteCount (MaxBufferSize)];
+ charByteBuffer = new byte [MaxBufferSize];
+ }
+
+ //
+ // We read the string here in small chunks. Also, we
+ // Attempt to optimize the common case of short strings.
+ //
+ StringBuilder sb = null;
+ do {
+ int readLen = Math.Min (MaxBufferSize, len);
+
+ int n = m_stream.Read (charByteBuffer, 0, readLen);
+ if (n == 0)
+ throw new EndOfStreamException();
+
+ int cch = decoder.GetChars (charByteBuffer, 0, n, 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);
+
+ if (sb == null)
+ // Len is a fairly good estimate of the number of chars in a string
+ // Most of the time 1 byte == 1 char
+ sb = new StringBuilder (len);
+
+ sb.Append (charBuffer, 0, cch);
+ len -= readLen;
+ } while (len > 0);
- return(new String(str));
+ return sb.ToString();
}
public virtual float ReadSingle() {
{
if(m_buffer.Length <= length) {
byte[] new_buffer=new byte[length];
- Array.Copy(m_buffer, new_buffer,
- m_buffer.Length);
+ Buffer.BlockCopyInternal (m_buffer, 0, new_buffer, 0, m_buffer.Length);
m_buffer=new_buffer;
}
}