2002-05-05 Nick Drochak <ndrochak@gol.com>
[mono.git] / mcs / class / corlib / System.IO / StreamReader.cs
1 //\r
2 // System.IO.StreamReader.cs\r
3 //\r
4 // Author:\r
5 //   Dietmar Maurer (dietmar@ximian.com)\r
6 //\r
7 // (C) Ximian, Inc.  http://www.ximian.com\r
8 //\r
9 \r
10 using System;\r
11 using System.Text;\r
12 \r
13 namespace System.IO {\r
14         [Serializable]\r
15         public class StreamReader : TextReader {\r
16 \r
17                 private const int DefaultBufferSize = 1024;\r
18                 private const int DefaultFileBufferSize = 4096;\r
19                 private const int MinimumBufferSize = 128;\r
20 \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
26 \r
27                 private int pos;\r
28 \r
29 \r
30                 private Encoding internalEncoding;\r
31                 private Decoder decoder;\r
32 \r
33                 private Stream internalStream;\r
34 \r
35                 [MonoTODO("Make Read methods return 0, etc.")]\r
36                 internal class NullStreamReader : StreamReader {\r
37                 }\r
38 \r
39                 public new static readonly StreamReader Null = (StreamReader)(new NullStreamReader());\r
40 \r
41                 internal StreamReader() {}\r
42 \r
43                 public StreamReader(Stream stream)\r
44                         : this (stream, null, false, DefaultBufferSize) { }\r
45 \r
46                 public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)\r
47                         : this (stream, null, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }\r
48 \r
49                 public StreamReader(Stream stream, Encoding encoding)\r
50                         : this (stream, encoding, false, DefaultBufferSize) { }\r
51 \r
52                 public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
53                         : this (stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize) { }\r
54                 \r
55                 public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)\r
56                 {\r
57                         Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);\r
58                 }\r
59 \r
60                 public StreamReader(string path)\r
61                         : this (path, null, false, DefaultFileBufferSize) { }\r
62 \r
63                 public StreamReader(string path, bool detectEncodingFromByteOrderMarks)\r
64                         : this (path, null, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }\r
65 \r
66                 public StreamReader(string path, Encoding encoding)\r
67                         : this (path, encoding, false, DefaultFileBufferSize) { }\r
68 \r
69                 public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)\r
70                         : this (path, encoding, detectEncodingFromByteOrderMarks, DefaultFileBufferSize) { }\r
71                 \r
72                 [MonoTODO]\r
73                 public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)\r
74                 {\r
75                         if (null == path)\r
76                                 throw new ArgumentNullException();\r
77                         if (String.Empty == path)\r
78                                 throw new ArgumentException();\r
79 \r
80                         Stream stream = (Stream) File.OpenRead (path);\r
81                         Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);\r
82                 }\r
83 \r
84                 [MonoTODO]\r
85                 protected void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)\r
86                 {\r
87                         if (null == stream)\r
88                                 throw new ArgumentNullException();\r
89                         if (!stream.CanRead)\r
90                                 throw new ArgumentException("Cannot read stream");\r
91 \r
92                         internalStream = stream;\r
93 \r
94                         // use detect encoding flag\r
95                         if (encoding == null) {\r
96                                 internalEncoding = Encoding.UTF8;\r
97                                 decoder = Encoding.UTF8.GetDecoder ();\r
98                         } else {\r
99                                 internalEncoding = encoding;\r
100                                 decoder = encoding.GetDecoder ();\r
101                         }\r
102 \r
103                         if (bufferSize < MinimumBufferSize)\r
104                                 bufferSize = MinimumBufferSize;\r
105 \r
106                         rgbEncoded = new byte [bufferSize];\r
107                         rgchDecoded = new char [internalEncoding.GetMaxCharCount (bufferSize)];\r
108                         pos = 0;\r
109                         cchDecoded = 0;\r
110                 }\r
111 \r
112                 public virtual Stream BaseStream\r
113                 {\r
114                         get {\r
115                                 return internalStream;\r
116                         }\r
117                 }\r
118 \r
119                 public virtual Encoding CurrentEncoding\r
120                 {\r
121                         get {\r
122                                 return internalEncoding;\r
123                         }\r
124                 }\r
125 \r
126                 public override void Close ()\r
127                 {\r
128                         Dispose (true);\r
129                 }\r
130 \r
131                 public void DiscardBufferedData ()\r
132                 {\r
133                         pos = 0;\r
134                         cchDecoded = 0;\r
135 \r
136 /* I'm sure there's no need to do all this\r
137                         if ((cchDecoded == null) || (pos == cchDecoded.Length))\r
138                                 return;\r
139 \r
140                         if (!internalStream.CanSeek)\r
141                                 return;\r
142 \r
143                         int seek_back = pos - cchDecoded.Length;\r
144                         internalStream.Seek (seek_back, SeekOrigin.Current);\r
145 */\r
146                 }\r
147 \r
148 \r
149                 // the buffer is empty, fill it again\r
150                 [MonoTODO ("handle byte order marks here")]\r
151                 private int ReadBuffer ()\r
152                 {\r
153                         pos = 0;\r
154                         int cbEncoded = 0;\r
155                         cchDecoded = 0;\r
156                         do      // keep looping until the decoder gives us some chars\r
157                         {\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
161 \r
162                                 if (cbEncoded == 0)\r
163                                         return 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
167 \r
168                         return cchDecoded;\r
169                 }\r
170 \r
171                 public override int Peek ()\r
172                 {\r
173                         if (!internalStream.CanSeek)\r
174                                 return -1;\r
175 \r
176                         if (pos >= cchDecoded && ReadBuffer () == 0)\r
177                                 return -1;\r
178 \r
179                         return rgchDecoded [pos];\r
180                 }\r
181 \r
182                 public override int Read ()\r
183                 {\r
184                         if (pos >= cchDecoded && ReadBuffer () == 0)\r
185                                 return -1;\r
186 \r
187                         return rgchDecoded [pos++];\r
188                 }\r
189 \r
190                 public override int Read (char[] dest_buffer, int index, int count)\r
191                 {\r
192                         if (dest_buffer == null)\r
193                                 throw new ArgumentException ();\r
194 \r
195                         if ((index < 0) || (count < 0))\r
196                                 throw new ArgumentOutOfRangeException ();\r
197 \r
198                         if (index + count > dest_buffer.Length)\r
199                                 throw new ArgumentException ();\r
200 \r
201                         int cchRead = 0;\r
202                         while (count > 0)\r
203                         {\r
204                                 if (pos >= cchDecoded && ReadBuffer () == 0)\r
205                                         return -1;\r
206 \r
207                                 int cch = Math.Min (cchDecoded - pos, count);\r
208                                 Array.Copy (rgchDecoded, pos, dest_buffer, index, cch);\r
209                                 pos += cch;\r
210                                 index += cch;\r
211                                 count -= cch;\r
212                                 cchRead += cch;\r
213                         }\r
214                         return cchRead;\r
215                 }\r
216 \r
217                 public override string ReadLine()\r
218                 {\r
219                         StringBuilder text = new StringBuilder ();\r
220 \r
221                         while (true) {\r
222                                 int c = Read ();\r
223 \r
224                                 if (c == -1) {                          // end of stream\r
225                                         if (text.Length == 0)\r
226                                                 return null;\r
227 \r
228                                         break;\r
229                                 }\r
230 \r
231                                 if (c == '\n')                          // newline\r
232                                         break;\r
233 \r
234                                 if (c == '\r' && Peek () == '\n') {     // cr, newline\r
235                                         Read ();\r
236                                         break;\r
237                                 }\r
238 \r
239                                 text.Append ((char) c);\r
240                         }\r
241 \r
242                         return text.ToString ();\r
243                 }\r
244 \r
245                 public override string ReadToEnd()\r
246                 {\r
247                         StringBuilder text = new StringBuilder ();\r
248 \r
249                         int c;\r
250                         while ((c = Read ()) != -1) {\r
251                                 text.Append ((char) c);\r
252                         }\r
253 \r
254                         if (text.Length == 0)\r
255                                 return String.Empty;\r
256                         return text.ToString ();\r
257                 }\r
258         }\r
259 }\r