Fri Jun 14 16:21:54 CEST 2002 Paolo Molaro <lupus@ximian.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                 private 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                         if (path.IndexOfAny (Path.InvalidPathChars) != -1)\r
80                                 throw new ArgumentException("path contains invalid characters");\r
81 \r
82                         string DirName = Path.GetDirectoryName(path);\r
83                         if (DirName != String.Empty && !Directory.Exists(DirName))\r
84                                 throw new DirectoryNotFoundException();\r
85                         if (!File.Exists(path))\r
86                                 throw new FileNotFoundException(path);\r
87 \r
88                         Stream stream = (Stream) File.OpenRead (path);\r
89                         Initialize (stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);\r
90                 }\r
91 \r
92                 [MonoTODO]\r
93                 protected void Initialize (Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)\r
94                 {\r
95                         if (null == stream)\r
96                                 throw new ArgumentNullException();\r
97                         if (!stream.CanRead)\r
98                                 throw new ArgumentException("Cannot read stream");\r
99 \r
100                         internalStream = stream;\r
101 \r
102                         // use detect encoding flag\r
103                         if (encoding == null) {\r
104                                 internalEncoding = Encoding.UTF8;\r
105                                 decoder = Encoding.UTF8.GetDecoder ();\r
106                         } else {\r
107                                 internalEncoding = encoding;\r
108                                 decoder = encoding.GetDecoder ();\r
109                         }\r
110 \r
111                         if (bufferSize < MinimumBufferSize)\r
112                                 bufferSize = MinimumBufferSize;\r
113 \r
114                         rgbEncoded = new byte [bufferSize];\r
115                         rgchDecoded = new char [internalEncoding.GetMaxCharCount (bufferSize)];\r
116                         pos = 0;\r
117                         cchDecoded = 0;\r
118                 }\r
119 \r
120                 public virtual Stream BaseStream\r
121                 {\r
122                         get {\r
123                                 return internalStream;\r
124                         }\r
125                 }\r
126 \r
127                 public virtual Encoding CurrentEncoding\r
128                 {\r
129                         get {\r
130                                 return internalEncoding;\r
131                         }\r
132                 }\r
133 \r
134                 public override void Close ()\r
135                 {\r
136                         Dispose (true);\r
137                 }\r
138 \r
139                 public void DiscardBufferedData ()\r
140                 {\r
141                         pos = 0;\r
142                         cchDecoded = 0;\r
143 \r
144 /* I'm sure there's no need to do all this\r
145                         if ((cchDecoded == null) || (pos == cchDecoded.Length))\r
146                                 return;\r
147 \r
148                         if (!internalStream.CanSeek)\r
149                                 return;\r
150 \r
151                         int seek_back = pos - cchDecoded.Length;\r
152                         internalStream.Seek (seek_back, SeekOrigin.Current);\r
153 */\r
154                 }\r
155 \r
156 \r
157                 // the buffer is empty, fill it again\r
158                 [MonoTODO ("handle byte order marks here")]\r
159                 private int ReadBuffer ()\r
160                 {\r
161                         pos = 0;\r
162                         int cbEncoded = 0;\r
163                         cchDecoded = 0;\r
164                         do      // keep looping until the decoder gives us some chars\r
165                         {\r
166                                 cbEncoded = internalStream.Read (rgbEncoded, 0, rgbEncoded.Length);\r
167                                 // TODO: remove this line when iconv is fixed\r
168                                 int bufcnt = decoder.GetCharCount (rgbEncoded, 0, cbEncoded);\r
169 \r
170                                 if (cbEncoded == 0)\r
171                                         return 0;\r
172                                 // TODO: remove byte order marks here\r
173                                 cchDecoded += decoder.GetChars (rgbEncoded, 0, cbEncoded, rgchDecoded, 0);\r
174                         } while (cchDecoded == 0);\r
175 \r
176                         return cchDecoded;\r
177                 }\r
178 \r
179                 public override int Peek ()\r
180                 {\r
181                         if (!internalStream.CanSeek)\r
182                                 return -1;\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 ()\r
191                 {\r
192                         if (pos >= cchDecoded && ReadBuffer () == 0)\r
193                                 return -1;\r
194 \r
195                         return rgchDecoded [pos++];\r
196                 }\r
197 \r
198                 public override int Read (char[] dest_buffer, int index, int count)\r
199                 {\r
200                         if (dest_buffer == null)\r
201                                 throw new ArgumentException ();\r
202 \r
203                         if ((index < 0) || (count < 0))\r
204                                 throw new ArgumentOutOfRangeException ();\r
205 \r
206                         if (index + count > dest_buffer.Length)\r
207                                 throw new ArgumentException ();\r
208 \r
209                         int cchRead = 0;\r
210                         while (count > 0)\r
211                         {\r
212                                 if (pos >= cchDecoded && ReadBuffer () == 0)\r
213                                         return cchRead > 0? cchRead: -1;\r
214 \r
215                                 int cch = Math.Min (cchDecoded - pos, count);\r
216                                 Array.Copy (rgchDecoded, pos, dest_buffer, index, cch);\r
217                                 pos += cch;\r
218                                 index += cch;\r
219                                 count -= cch;\r
220                                 cchRead += cch;\r
221                         }\r
222                         return cchRead;\r
223                 }\r
224 \r
225                 public override string ReadLine()\r
226                 {\r
227                         StringBuilder text = new StringBuilder ();\r
228 \r
229                         while (true) {\r
230                                 int c = Read ();\r
231 \r
232                                 if (c == -1) {                          // end of stream\r
233                                         if (text.Length == 0)\r
234                                                 return null;\r
235 \r
236                                         break;\r
237                                 }\r
238 \r
239                                 if (c == '\n')                          // newline\r
240                                         break;\r
241 \r
242                                 if (c == '\r' && Peek () == '\n') {     // cr, newline\r
243                                         Read ();\r
244                                         break;\r
245                                 }\r
246 \r
247                                 text.Append ((char) c);\r
248                         }\r
249 \r
250                         return text.ToString ();\r
251                 }\r
252 \r
253                 public override string ReadToEnd()\r
254                 {\r
255                         StringBuilder text = new StringBuilder ();\r
256 \r
257                         int c;\r
258                         while ((c = Read ()) != -1) {\r
259                                 text.Append ((char) c);\r
260                         }\r
261 \r
262                         if (text.Length == 0)\r
263                                 return String.Empty;\r
264                         return text.ToString ();\r
265                 }\r
266         }\r
267 }\r