X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.IO%2FStreamReader.cs;h=279922b43edb9c6eea0923df3a38070fdaf1864b;hb=2d23bfcbce7a3f7e54dcd5911adb88b244baca35;hp=fe80c2d57d0e8174245c4c051bc95db6383ebb53;hpb=c6856bc091391c276d8fc87e379fb56061fdb8c3;p=mono.git diff --git a/mcs/class/corlib/System.IO/StreamReader.cs b/mcs/class/corlib/System.IO/StreamReader.cs index fe80c2d57d0..279922b43ed 100644 --- a/mcs/class/corlib/System.IO/StreamReader.cs +++ b/mcs/class/corlib/System.IO/StreamReader.cs @@ -4,6 +4,7 @@ // Author: // Dietmar Maurer (dietmar@ximian.com) // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@gmail.com) // // (C) Ximian, Inc. http://www.ximian.com // Copyright (C) 2004 Novell (http://www.novell.com) @@ -38,6 +39,7 @@ using System.Runtime.InteropServices; namespace System.IO { [Serializable] + [ComVisible (true)] public class StreamReader : TextReader { const int DefaultBufferSize = 1024; @@ -48,11 +50,16 @@ namespace System.IO { // The input buffer // byte [] input_buffer; + + // Input buffer ready for recycling + static byte [] input_buffer_recycle; + static object input_buffer_recycle_lock = new object (); // // The decoded buffer from the above input buffer // char [] decoded_buffer; + static char[] decoded_buffer_recycle; // // Decoded bytes in decoded_buffer. @@ -115,40 +122,40 @@ namespace System.IO { } } - public new static readonly StreamReader Null = (StreamReader)(new NullStreamReader()); + public new static readonly StreamReader Null = new NullStreamReader (); internal StreamReader() {} public StreamReader(Stream stream) : this (stream, Encoding.UTF8Unmarked, true, DefaultBufferSize) { } - public StreamReader(Stream stream, bool detect_encoding_from_bytemarks) - : this (stream, Encoding.UTF8Unmarked, detect_encoding_from_bytemarks, DefaultBufferSize) { } + public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks) + : this (stream, Encoding.UTF8Unmarked, detectEncodingFromByteOrderMarks, DefaultBufferSize) { } public StreamReader(Stream stream, Encoding encoding) : this (stream, encoding, true, DefaultBufferSize) { } - public StreamReader(Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks) - : this (stream, encoding, detect_encoding_from_bytemarks, DefaultBufferSize) { } + public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks) + : this (stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { } - public StreamReader(Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size) + public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) { - Initialize (stream, encoding, detect_encoding_from_bytemarks, buffer_size); + Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize); } public StreamReader(string path) : this (path, Encoding.UTF8Unmarked, true, DefaultFileBufferSize) { } - public StreamReader(string path, bool detect_encoding_from_bytemarks) - : this (path, Encoding.UTF8Unmarked, detect_encoding_from_bytemarks, DefaultFileBufferSize) { } + public StreamReader(string path, bool detectEncodingFromByteOrderMarks) + : this (path, Encoding.UTF8Unmarked, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { } public StreamReader(string path, Encoding encoding) : this (path, encoding, true, DefaultFileBufferSize) { } - public StreamReader(string path, Encoding encoding, bool detect_encoding_from_bytemarks) - : this (path, encoding, detect_encoding_from_bytemarks, DefaultFileBufferSize) { } + public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks) + : this (path, encoding, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { } - public StreamReader(string path, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size) + public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) { if (null == path) throw new ArgumentNullException("path"); @@ -158,14 +165,14 @@ namespace System.IO { throw new ArgumentException("path contains invalid characters"); if (null == encoding) throw new ArgumentNullException ("encoding"); - if (buffer_size <= 0) - throw new ArgumentOutOfRangeException ("buffer_size", "The minimum size of the buffer must be positive"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException ("bufferSize", "The minimum size of the buffer must be positive"); Stream stream = (Stream) File.OpenRead (path); - Initialize (stream, encoding, detect_encoding_from_bytemarks, buffer_size); + Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize); } - internal void Initialize (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size) + internal void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize) { if (null == stream) throw new ArgumentNullException ("stream"); @@ -173,23 +180,54 @@ namespace System.IO { throw new ArgumentNullException ("encoding"); if (!stream.CanRead) throw new ArgumentException ("Cannot read stream"); - if (buffer_size <= 0) - throw new ArgumentOutOfRangeException ("buffer_size", "The minimum size of the buffer must be positive"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException ("bufferSize", "The minimum size of the buffer must be positive"); - if (buffer_size < MinimumBufferSize) - buffer_size = MinimumBufferSize; + if (bufferSize < MinimumBufferSize) + bufferSize = MinimumBufferSize; + + // since GetChars() might add flushed character, it + // should have additional char buffer for extra 1 + // (probably 1 is ok, but might be insufficient. I'm not sure) + var decoded_buffer_size = encoding.GetMaxCharCount (bufferSize) + 1; + + // + // Instead of allocating a new default buffer use the + // last one if there is any available + // + if (bufferSize <= DefaultBufferSize && input_buffer_recycle != null) { + lock (input_buffer_recycle_lock) { + if (input_buffer_recycle != null) { + input_buffer = input_buffer_recycle; + input_buffer_recycle = null; + } + + if (decoded_buffer_recycle != null && decoded_buffer_size <= decoded_buffer_recycle.Length) { + decoded_buffer = decoded_buffer_recycle; + decoded_buffer_recycle = null; + } + } + } + + if (input_buffer == null) + input_buffer = new byte [bufferSize]; + else + Array.Clear (input_buffer, 0, bufferSize); + + if (decoded_buffer == null) + decoded_buffer = new char [decoded_buffer_size]; + else + Array.Clear (decoded_buffer, 0, decoded_buffer_size); - base_stream = stream; - input_buffer = new byte [buffer_size]; - this.buffer_size = buffer_size; + base_stream = stream; + this.buffer_size = bufferSize; this.encoding = encoding; decoder = encoding.GetDecoder (); byte [] preamble = encoding.GetPreamble (); - do_checks = detect_encoding_from_bytemarks ? 1 : 0; + do_checks = detectEncodingFromByteOrderMarks ? 1 : 0; do_checks += (preamble.Length == 0) ? 0 : 2; - decoded_buffer = new char [encoding.GetMaxCharCount (buffer_size)]; decoded_count = 0; pos = 0; } @@ -210,11 +248,9 @@ namespace System.IO { } } -#if NET_2_0 public bool EndOfStream { get { return Peek () < 0; } } -#endif public override void Close () { @@ -226,6 +262,18 @@ namespace System.IO { if (disposing && base_stream != null) base_stream.Close (); + if (input_buffer != null && input_buffer.Length == DefaultBufferSize && input_buffer_recycle == null) { + lock (input_buffer_recycle_lock) { + if (input_buffer_recycle == null) { + input_buffer_recycle = input_buffer; + } + + if (decoded_buffer_recycle == null) { + decoded_buffer_recycle = decoded_buffer; + } + } + } + input_buffer = null; decoded_buffer = null; encoding = null; @@ -263,8 +311,8 @@ namespace System.IO { this.encoding = Encoding.BigEndianUnicode; return 2; } - - if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe){ + if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe && count < 4) { + // If we don't have enough bytes we can't check for UTF32, so use Unicode this.encoding = Encoding.Unicode; return 2; } @@ -276,6 +324,31 @@ namespace System.IO { this.encoding = Encoding.UTF8Unmarked; return 3; } + + if (count < 4) { + if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe && input_buffer [2] != 0) { + this.encoding = Encoding.Unicode; + return 2; + } + return 0; + } + + if (input_buffer [0] == 0 && input_buffer [1] == 0 + && input_buffer [2] == 0xfe && input_buffer [3] == 0xff) + { + this.encoding = Encoding.BigEndianUTF32; + return 4; + } + + if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe) { + if (input_buffer [2] == 0 && input_buffer[3] == 0) { + this.encoding = Encoding.UTF32; + return 4; + } + + this.encoding = Encoding.Unicode; + return 2; + } } return 0; @@ -310,6 +383,10 @@ namespace System.IO { Encoding old = encoding; parse_start = DoChecks (cbEncoded); if (old != encoding){ + int old_decoded_size = old.GetMaxCharCount (buffer_size) + 1; + int new_decoded_size = encoding.GetMaxCharCount (buffer_size) + 1; + if (old_decoded_size != new_decoded_size) + decoded_buffer = new char [new_decoded_size]; decoder = encoding.GetDecoder (); } do_checks = 0; @@ -323,16 +400,29 @@ namespace System.IO { return decoded_count; } + // + // Peek can block: + // http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=96484 + // public override int Peek () { if (base_stream == null) throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader"); - if (pos >= decoded_count && (mayBlock || ReadBuffer () == 0)) + if (pos >= decoded_count && ReadBuffer () == 0) return -1; return decoded_buffer [pos]; } + // + // Used internally by our console, as it previously depended on Peek() being a + // routine that would not block. + // + internal bool DataAvailable () + { + return pos < decoded_count; + } + public override int Read () { if (base_stream == null) @@ -343,19 +433,19 @@ namespace System.IO { return decoded_buffer [pos++]; } - public override int Read ([In, Out] char[] dest_buffer, int index, int count) + public override int Read ([In, Out] char[] buffer, int index, int count) { if (base_stream == null) throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader"); - if (dest_buffer == null) - throw new ArgumentNullException ("dest_buffer"); + if (buffer == null) + throw new ArgumentNullException ("buffer"); if (index < 0) throw new ArgumentOutOfRangeException ("index", "< 0"); if (count < 0) throw new ArgumentOutOfRangeException ("count", "< 0"); // re-ordered to avoid possible integer overflow - if (index > dest_buffer.Length - count) - throw new ArgumentException ("index + count > dest_buffer.Length"); + if (index > buffer.Length - count) + throw new ArgumentException ("index + count > buffer.Length"); int chars_read = 0; while (count > 0) @@ -364,7 +454,7 @@ namespace System.IO { return chars_read > 0 ? chars_read : 0; int cch = Math.Min (decoded_count - pos, count); - Array.Copy (decoded_buffer, pos, dest_buffer, index, cch); + Array.Copy (decoded_buffer, pos, buffer, index, cch); pos += cch; index += cch; count -= cch; @@ -391,6 +481,10 @@ namespace System.IO { return res; } else if (foundCR) { foundCR = false; + if (pos == 0) + return -2; // Need to flush the current buffered line. + // This is a \r at the end of the previous decoded buffer that + // is not followed by a \n in the current decoded buffer. return pos - 1; } @@ -412,6 +506,8 @@ namespace System.IO { int end = FindNextEOL (); if (end < decoded_count && end >= begin) return new string (decoded_buffer, begin, end - begin); + else if (end == -2) + return line_builder.ToString (0, line_builder.Length); if (line_builder == null) line_builder = new StringBuilder (); @@ -442,7 +538,8 @@ namespace System.IO { return sb.ToString (0, sb.Length); } return line_builder.ToString (0, line_builder.Length); - } + } else if (end == -2) + return line_builder.ToString (0, line_builder.Length); } }