X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.IO%2FStreamReader.cs;h=70e08f91967a70e2ed9f1fb55ce8af40e325f97d;hb=7c970f8ee1f635da8575bcf58d89c16bb5c2ace1;hp=33682ff59f60edcc60dff39451bfd11ca188258b;hpb=0f62bbab300fec7f1730977ceb9a8f1c7af7d432;p=mono.git diff --git a/mcs/class/corlib/System.IO/StreamReader.cs b/mcs/class/corlib/System.IO/StreamReader.cs index 33682ff59f6..70e08f91967 100644 --- a/mcs/class/corlib/System.IO/StreamReader.cs +++ b/mcs/class/corlib/System.IO/StreamReader.cs @@ -6,57 +6,80 @@ // Miguel de Icaza (miguel@ximian.com) // // (C) Ximian, Inc. http://www.ximian.com +// Copyright (C) 2004 Novell (http://www.novell.com) +// + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Text; - +using System.Runtime.InteropServices; namespace System.IO { [Serializable] +#if NET_2_0 + [ComVisible (true)] +#endif public class StreamReader : TextReader { - private const int DefaultBufferSize = 1024; - private const int DefaultFileBufferSize = 4096; - private const int MinimumBufferSize = 128; + const int DefaultBufferSize = 1024; + const int DefaultFileBufferSize = 4096; + const int MinimumBufferSize = 128; // // The input buffer // - private byte [] input_buffer; + byte [] input_buffer; // // The decoded buffer from the above input buffer // - private char [] decoded_buffer; + char [] decoded_buffer; // // Decoded bytes in decoded_buffer. // - private int decoded_count; + int decoded_count; // // Current position in the decoded_buffer // - private int pos; + int pos; // // The buffer size that we are using // - private int buffer_size; - - // - // Index into `input_buffer' where we start decoding - // - private int parse_start; + int buffer_size; int do_checks; - private Encoding encoding; - private Decoder decoder; + Encoding encoding; + Decoder decoder; - private Stream base_stream; - private bool mayBlock; + Stream base_stream; + bool mayBlock; + StringBuilder line_builder; private class NullStreamReader : StreamReader { public override int Peek () @@ -69,7 +92,7 @@ namespace System.IO { return -1; } - public override int Read (char[] buffer, int index, int count) + public override int Read ([In, Out] char[] buffer, int index, int count) { return 0; } @@ -136,23 +159,25 @@ namespace System.IO { throw new ArgumentException("Empty path not allowed"); if (path.IndexOfAny (Path.InvalidPathChars) != -1) throw new ArgumentException("path contains invalid characters"); - - string DirName = Path.GetDirectoryName(path); - if (DirName != String.Empty && !Directory.Exists(DirName)) - throw new DirectoryNotFoundException ("Directory '" + DirName + "' not found."); - if (!File.Exists(path)) - throw new FileNotFoundException(path); + 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"); Stream stream = (Stream) File.OpenRead (path); Initialize (stream, encoding, detect_encoding_from_bytemarks, buffer_size); } - protected void Initialize (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size) + internal void Initialize (Stream stream, Encoding encoding, bool detect_encoding_from_bytemarks, int buffer_size) { if (null == stream) - throw new ArgumentNullException("stream"); + throw new ArgumentNullException ("stream"); + if (null == encoding) + throw new ArgumentNullException ("encoding"); if (!stream.CanRead) - throw new ArgumentException("Cannot read stream"); + 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 (buffer_size < MinimumBufferSize) buffer_size = MinimumBufferSize; @@ -167,7 +192,10 @@ namespace System.IO { do_checks = detect_encoding_from_bytemarks ? 1 : 0; do_checks += (preamble.Length == 0) ? 0 : 2; - decoded_buffer = new char [encoding.GetMaxCharCount (buffer_size)]; + // 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) + decoded_buffer = new char [encoding.GetMaxCharCount (buffer_size) + 1]; decoded_count = 0; pos = 0; } @@ -188,6 +216,12 @@ namespace System.IO { } } +#if NET_2_0 + public bool EndOfStream { + get { return Peek () < 0; } + } +#endif + public override void Close () { Dispose (true); @@ -231,13 +265,15 @@ namespace System.IO { if (count < 2) return 0; - if (input_buffer [0] == 0xfe && input_buffer [1] == 0xff){ - this.encoding = Encoding.BigEndianUnicode; +#if !NET_2_0 + if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe){ + this.encoding = Encoding.Unicode; return 2; } +#endif - if (input_buffer [0] == 0xff && input_buffer [1] == 0xfe){ - this.encoding = Encoding.Unicode; + if (input_buffer [0] == 0xfe && input_buffer [1] == 0xff){ + this.encoding = Encoding.BigEndianUnicode; return 2; } @@ -248,10 +284,45 @@ namespace System.IO { this.encoding = Encoding.UTF8Unmarked; return 3; } + +#if NET_2_0 + 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; + } +#endif } return 0; } + + public void DiscardBufferedData () + { + pos = decoded_count = 0; + mayBlock = false; + // Discard internal state of the decoder too. + decoder = encoding.GetDecoder (); + } // the buffer is empty, fill it again private int ReadBuffer () @@ -266,7 +337,7 @@ namespace System.IO { { cbEncoded = base_stream.Read (input_buffer, 0, buffer_size); - if (cbEncoded == 0) + if (cbEncoded <= 0) return 0; mayBlock = (cbEncoded < buffer_size); @@ -283,12 +354,14 @@ namespace System.IO { decoded_count += decoder.GetChars (input_buffer, parse_start, cbEncoded, decoded_buffer, 0); parse_start = 0; } while (decoded_count == 0); - + return decoded_count; } 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)) return -1; @@ -297,22 +370,27 @@ namespace System.IO { public override int Read () { + if (base_stream == null) + throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader"); if (pos >= decoded_count && ReadBuffer () == 0) return -1; return decoded_buffer [pos++]; } - public override int Read (char[] dest_buffer, int index, int count) + public override int Read ([In, Out] char[] dest_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 ArgumentException (); - - if ((index < 0) || (count < 0)) - throw new ArgumentOutOfRangeException (); - - if (index + count > dest_buffer.Length) - throw new ArgumentException (); + throw new ArgumentNullException ("dest_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"); int chars_read = 0; while (count > 0) @@ -326,59 +404,95 @@ namespace System.IO { index += cch; count -= cch; chars_read += cch; + if (mayBlock) + break; } return chars_read; } - public override string ReadLine() + bool foundCR; + int FindNextEOL () { - bool foundCR = false; - StringBuilder text = new StringBuilder (); + char c = '\0'; + for (; pos < decoded_count; pos++) { + c = decoded_buffer [pos]; + if (c == '\n') { + pos++; + int res = (foundCR) ? (pos - 2) : (pos - 1); + if (res < 0) + res = 0; // if a new buffer starts with a \n and there was a \r at + // the end of the previous one, we get here. + foundCR = false; + return res; + } else if (foundCR) { + foundCR = false; + return pos - 1; + } - while (true) { - int c = Read (); + foundCR = (c == '\r'); + } - if (c == -1) { // end of stream - if (text.Length == 0) - return null; + return -1; + } - if (foundCR) - text.Length--; + public override string ReadLine() + { + if (base_stream == null) + throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader"); - break; - } + if (pos >= decoded_count && ReadBuffer () == 0) + return null; - if (c == '\n') { // newline - if ((text.Length > 0) && (text [text.Length - 1] == '\r')) - text.Length--; + int begin = pos; + int end = FindNextEOL (); + if (end < decoded_count && end >= begin) + return new string (decoded_buffer, begin, end - begin); - foundCR = false; - break; - } else if (foundCR) { - pos--; - text.Length--; - break; - } + if (line_builder == null) + line_builder = new StringBuilder (); + else + line_builder.Length = 0; - if (c == '\r') - foundCR = true; - + while (true) { + if (foundCR) // don't include the trailing CR if present + decoded_count--; + + line_builder.Append (decoded_buffer, begin, decoded_count - begin); + if (ReadBuffer () == 0) { + if (line_builder.Capacity > 32768) { + StringBuilder sb = line_builder; + line_builder = null; + return sb.ToString (0, sb.Length); + } + return line_builder.ToString (0, line_builder.Length); + } - text.Append ((char) c); + begin = pos; + end = FindNextEOL (); + if (end < decoded_count && end >= begin) { + line_builder.Append (decoded_buffer, begin, end - begin); + if (line_builder.Capacity > 32768) { + StringBuilder sb = line_builder; + line_builder = null; + return sb.ToString (0, sb.Length); + } + return line_builder.ToString (0, line_builder.Length); + } } - - return text.ToString (); } public override string ReadToEnd() { + if (base_stream == null) + throw new ObjectDisposedException ("StreamReader", "Cannot read from a closed StreamReader"); + StringBuilder text = new StringBuilder (); int size = decoded_buffer.Length; char [] buffer = new char [size]; int len; - while ((len = Read (buffer, 0, size)) != 0) + while ((len = Read (buffer, 0, size)) > 0) text.Append (buffer, 0, len); return text.ToString ();