2 // System.IO.StreamReader.cs
\r
5 // Dietmar Maurer (dietmar@ximian.com)
\r
7 // (C) Ximian, Inc. http://www.ximian.com
\r
13 namespace System.IO {
\r
15 public class StreamReader : TextReader {
\r
17 private const int DefaultBufferSize = 1024;
\r
18 private const int DefaultFileBufferSize = 4096;
\r
19 private const int MinimumBufferSize = 128;
\r
21 // buffering members
\r
22 private byte [] rgbEncoded;
\r
23 // private int cbEncoded;
\r
24 private char [] rgchDecoded;
\r
25 private int cchDecoded;
\r
30 private Encoding internalEncoding;
\r
31 private Decoder decoder;
\r
33 private Stream internalStream;
\r
35 [MonoTODO("Make Read methods return 0, etc.")]
\r
36 internal class NullStreamReader : StreamReader {
\r
39 public new static readonly StreamReader Null = (StreamReader)(new NullStreamReader());
\r
41 internal StreamReader() {}
\r
43 public StreamReader(Stream stream)
\r
44 : this (stream, null, false, DefaultBufferSize) { }
\r
46 public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
\r
47 : this (stream, null, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
\r
49 public StreamReader(Stream stream, Encoding encoding)
\r
50 : this (stream, encoding, false, DefaultBufferSize) { }
\r
52 public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
\r
53 : this (stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }
\r
55 public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
\r
57 Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
\r
60 public StreamReader(string path)
\r
61 : this (path, null, false, DefaultFileBufferSize) { }
\r
63 public StreamReader(string path, bool detectEncodingFromByteOrderMarks)
\r
64 : this (path, null, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
\r
66 public StreamReader(string path, Encoding encoding)
\r
67 : this (path, encoding, false, DefaultFileBufferSize) { }
\r
69 public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
\r
70 : this (path, encoding, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }
\r
73 public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
\r
76 throw new ArgumentNullException();
\r
77 if (String.Empty == path)
\r
78 throw new ArgumentException();
\r
80 Stream stream = (Stream) File.OpenRead (path);
\r
81 Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
\r
85 protected void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
\r
88 throw new ArgumentNullException();
\r
89 if (!stream.CanRead)
\r
90 throw new ArgumentException("Cannot read stream");
\r
92 internalStream = stream;
\r
94 // use detect encoding flag
\r
95 if (encoding == null) {
\r
96 internalEncoding = Encoding.UTF8;
\r
97 decoder = Encoding.UTF8.GetDecoder ();
\r
99 internalEncoding = encoding;
\r
100 decoder = encoding.GetDecoder ();
\r
103 if (bufferSize < MinimumBufferSize)
\r
104 bufferSize = MinimumBufferSize;
\r
106 rgbEncoded = new byte [bufferSize];
\r
107 rgchDecoded = new char [internalEncoding.GetMaxCharCount (bufferSize)];
\r
112 public virtual Stream BaseStream
\r
115 return internalStream;
\r
119 public virtual Encoding CurrentEncoding
\r
122 return internalEncoding;
\r
126 public override void Close ()
\r
131 public void DiscardBufferedData ()
\r
136 /* I'm sure there's no need to do all this
\r
137 if ((cchDecoded == null) || (pos == cchDecoded.Length))
\r
140 if (!internalStream.CanSeek)
\r
143 int seek_back = pos - cchDecoded.Length;
\r
144 internalStream.Seek (seek_back, SeekOrigin.Current);
\r
149 // the buffer is empty, fill it again
\r
150 [MonoTODO ("handle byte order marks here")]
\r
151 private int ReadBuffer ()
\r
156 do // keep looping until the decoder gives us some chars
\r
158 cbEncoded = internalStream.Read (rgbEncoded, 0, rgbEncoded.Length);
\r
159 // TODO: remove this line when iconv is fixed
\r
160 int bufcnt = decoder.GetCharCount (rgbEncoded, 0, cbEncoded);
\r
162 if (cbEncoded == 0)
\r
164 // TODO: remove byte order marks here
\r
165 cchDecoded += decoder.GetChars (rgbEncoded, 0, cbEncoded, rgchDecoded, 0);
\r
166 } while (cchDecoded == 0);
\r
171 public override int Peek ()
\r
173 if (!internalStream.CanSeek)
\r
176 if (pos >= cchDecoded && ReadBuffer () == 0)
\r
179 return rgchDecoded [pos];
\r
182 public override int Read ()
\r
184 if (pos >= cchDecoded && ReadBuffer () == 0)
\r
187 return rgchDecoded [pos++];
\r
190 public override int Read (char[] dest_buffer, int index, int count)
\r
192 if (dest_buffer == null)
\r
193 throw new ArgumentException ();
\r
195 if ((index < 0) || (count < 0))
\r
196 throw new ArgumentOutOfRangeException ();
\r
198 if (index + count > dest_buffer.Length)
\r
199 throw new ArgumentException ();
\r
204 if (pos >= cchDecoded && ReadBuffer () == 0)
\r
207 int cch = Math.Min (cchDecoded - pos, count);
\r
208 Array.Copy (rgchDecoded, pos, dest_buffer, index, cch);
\r
217 public override string ReadLine()
\r
219 StringBuilder text = new StringBuilder ();
\r
224 if (c == -1) { // end of stream
\r
225 if (text.Length == 0)
\r
231 if (c == '\n') // newline
\r
234 if (c == '\r' && Peek () == '\n') { // cr, newline
\r
239 text.Append ((char) c);
\r
242 return text.ToString ();
\r
245 public override string ReadToEnd()
\r
247 StringBuilder text = new StringBuilder ();
\r
250 while ((c = Read ()) != -1) {
\r
251 text.Append ((char) c);
\r
254 if (text.Length == 0)
\r
255 return String.Empty;
\r
256 return text.ToString ();
\r