Handle relocatable libMonoPosixHelper.so when --libdir= isn't lib/
[mono.git] / mcs / class / referencesource / mscorlib / system / io / textreader.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  TextReader
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: Abstract base class for all Text-only Readers.
14 ** Subclasses will include StreamReader & StringReader.
15 **
16 **
17 ===========================================================*/
18
19 using System;
20 using System.Text;
21 using System.Runtime.InteropServices;
22 using System.Runtime.CompilerServices;
23 using System.Reflection;
24 using System.Security.Permissions;
25 using System.Diagnostics.CodeAnalysis;
26 using System.Diagnostics.Contracts;
27 #if FEATURE_ASYNC_IO
28 using System.Threading;
29 using System.Threading.Tasks;
30 #endif
31
32 namespace System.IO {
33     // This abstract base class represents a reader that can read a sequential
34     // stream of characters.  This is not intended for reading bytes -
35     // there are methods on the Stream class to read bytes.
36     // A subclass must minimally implement the Peek() and Read() methods.
37     //
38     // This class is intended for character input, not bytes.  
39     // There are methods on the Stream class for reading bytes. 
40     [Serializable]
41     [ComVisible(true)]
42 #if FEATURE_REMOTING
43     public abstract class TextReader : MarshalByRefObject, IDisposable {
44 #else // FEATURE_REMOTING
45     public abstract class TextReader : IDisposable {
46 #endif // FEATURE_REMOTING
47
48 #if FEATURE_ASYNC_IO
49         [NonSerialized]
50         private static Func<object, string> _ReadLineDelegate = state => ((TextReader)state).ReadLine();
51
52         [NonSerialized]
53         private static Func<object, int> _ReadDelegate = state => 
54         {
55             Tuple<TextReader, char[], int, int> tuple = (Tuple<TextReader, char[], int, int>)state;
56             return tuple.Item1.Read(tuple.Item2, tuple.Item3, tuple.Item4);
57         };
58 #endif //FEATURE_ASYNC_IO
59
60         public static readonly TextReader Null = new NullTextReader();
61     
62         protected TextReader() {}
63     
64         // Closes this TextReader and releases any system resources associated with the
65         // TextReader. Following a call to Close, any operations on the TextReader
66         // may raise exceptions.
67         // 
68         // This default method is empty, but descendant classes can override the
69         // method to provide the appropriate functionality.
70         public virtual void Close() 
71         {
72             Dispose(true);
73             GC.SuppressFinalize(this);
74         }
75
76         public void Dispose()
77         {
78             Dispose(true);
79             GC.SuppressFinalize(this);
80         }
81
82         protected virtual void Dispose(bool disposing)
83         {
84         }
85
86         // Returns the next available character without actually reading it from
87         // the input stream. The current position of the TextReader is not changed by
88         // this operation. The returned value is -1 if no further characters are
89         // available.
90         // 
91         // This default method simply returns -1.
92         //
93         [Pure]
94         public virtual int Peek() 
95         {
96             Contract.Ensures(Contract.Result<int>() >= -1);
97
98             return -1;
99         }
100     
101         // Reads the next character from the input stream. The returned value is
102         // -1 if no further characters are available.
103         // 
104         // This default method simply returns -1.
105         //
106         public virtual int Read()
107         {
108             Contract.Ensures(Contract.Result<int>() >= -1);
109             return -1;
110         }
111     
112         // Reads a block of characters. This method will read up to
113         // count characters from this TextReader into the
114         // buffer character array starting at position
115         // index. Returns the actual number of characters read.
116         //
117         public virtual int Read([In, Out] char[] buffer, int index, int count) 
118         {
119             if (buffer==null)
120                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
121             if (index < 0)
122                 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
123             if (count < 0)
124                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
125             if (buffer.Length - index < count)
126                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
127             Contract.Ensures(Contract.Result<int>() >= 0);
128             Contract.Ensures(Contract.Result<int>() <= Contract.OldValue(count));
129             Contract.EndContractBlock();
130     
131             int n = 0;
132             do {
133                 int ch = Read();
134                 if (ch == -1) break;
135                 buffer[index + n++] = (char)ch;
136             } while (n < count);
137             return n;
138         }
139
140         // Reads all characters from the current position to the end of the 
141         // TextReader, and returns them as one string.
142         public virtual String ReadToEnd()
143         {
144             Contract.Ensures(Contract.Result<String>() != null);
145
146             char[] chars = new char[4096];
147             int len;
148             StringBuilder sb = new StringBuilder(4096);
149             while((len=Read(chars, 0, chars.Length)) != 0) 
150             {
151                 sb.Append(chars, 0, len);
152             }
153             return sb.ToString();
154         }
155
156         // Blocking version of read.  Returns only when count
157         // characters have been read or the end of the file was reached.
158         // 
159         public virtual int ReadBlock([In, Out] char[] buffer, int index, int count) 
160         {
161             Contract.Ensures(Contract.Result<int>() >= 0);
162             Contract.Ensures(Contract.Result<int>() <= count);
163
164             int i, n = 0;
165             do {
166                 n += (i = Read(buffer, index + n, count - n));
167             } while (i > 0 && n < count);
168             return n;
169         }
170
171         // Reads a line. A line is defined as a sequence of characters followed by
172         // a carriage return ('\r'), a line feed ('\n'), or a carriage return
173         // immediately followed by a line feed. The resulting string does not
174         // contain the terminating carriage return and/or line feed. The returned
175         // value is null if the end of the input stream has been reached.
176         //
177         public virtual String ReadLine() 
178         {
179             StringBuilder sb = new StringBuilder();
180             while (true) {
181                 int ch = Read();
182                 if (ch == -1) break;
183                 if (ch == '\r' || ch == '\n') 
184                 {
185                     if (ch == '\r' && Peek() == '\n') Read();
186                     return sb.ToString();
187                 }
188                 sb.Append((char)ch);
189             }
190             if (sb.Length > 0) return sb.ToString();
191             return null;
192         }
193
194 #if FEATURE_ASYNC_IO
195         #region Task based Async APIs
196         [HostProtection(ExternalThreading=true)]
197         [ComVisible(false)]
198         public virtual Task<String> ReadLineAsync()
199         {
200             return Task<String>.Factory.StartNew(_ReadLineDelegate, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
201         }
202
203         [HostProtection(ExternalThreading=true)]
204         [ComVisible(false)]
205         public async virtual Task<String> ReadToEndAsync()
206         {
207             char[] chars = new char[4096];
208             int len;
209             StringBuilder sb = new StringBuilder(4096);
210             while((len = await ReadAsyncInternal(chars, 0, chars.Length).ConfigureAwait(false)) != 0) 
211             {
212                 sb.Append(chars, 0, len);
213             }
214             return sb.ToString();
215         }
216
217         [HostProtection(ExternalThreading=true)]
218         [ComVisible(false)]
219         public virtual Task<int> ReadAsync(char[] buffer, int index, int count)
220         {
221             if (buffer==null)
222                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
223             if (index < 0 || count < 0)
224                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
225             if (buffer.Length - index < count)
226                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
227             Contract.EndContractBlock();
228
229             return ReadAsyncInternal(buffer, index, count);
230         }
231
232         internal virtual Task<int> ReadAsyncInternal(char[] buffer, int index, int count)
233         {
234             Contract.Requires(buffer != null);
235             Contract.Requires(index >= 0);
236             Contract.Requires(count >= 0);
237             Contract.Requires(buffer.Length - index >= count);
238
239             Tuple<TextReader, char[], int, int> tuple = new Tuple<TextReader, char[], int, int>(this, buffer, index, count);
240             return Task<int>.Factory.StartNew(_ReadDelegate, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
241         }
242
243         [HostProtection(ExternalThreading=true)]
244         [ComVisible(false)]
245         public virtual Task<int> ReadBlockAsync(char[] buffer, int index, int count)
246         {
247             if (buffer==null)
248                 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
249             if (index < 0 || count < 0)
250                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
251             if (buffer.Length - index < count)
252                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
253
254             Contract.EndContractBlock();
255
256             return ReadBlockAsyncInternal(buffer, index, count);
257          }
258
259         [HostProtection(ExternalThreading=true)]
260         private async Task<int> ReadBlockAsyncInternal(char[] buffer, int index, int count)
261         {
262             Contract.Requires(buffer != null);
263             Contract.Requires(index >= 0);
264             Contract.Requires(count >= 0);
265             Contract.Requires(buffer.Length - index >= count);
266
267             int i, n = 0;
268             do
269             {
270                 i = await ReadAsyncInternal(buffer, index + n, count - n).ConfigureAwait(false);
271                 n += i;
272             } while (i > 0 && n < count);
273
274             return n;
275         }
276         #endregion
277 #endif //FEATURE_ASYNC_IO
278
279         [HostProtection(Synchronization=true)]
280         public static TextReader Synchronized(TextReader reader) 
281         {
282             if (reader==null)
283                 throw new ArgumentNullException("reader");
284             Contract.Ensures(Contract.Result<TextReader>() != null);
285             Contract.EndContractBlock();
286
287             if (reader is SyncTextReader)
288                 return reader;
289             
290             return new SyncTextReader(reader);
291         }
292         
293         [Serializable]
294         private sealed class NullTextReader : TextReader
295         {
296             public NullTextReader(){}
297
298             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
299             public override int Read(char[] buffer, int index, int count) 
300             {
301                 return 0;
302             }
303             
304             public override String ReadLine() 
305             {
306                 return null;
307             }
308         }
309         
310         [Serializable]
311         internal sealed class SyncTextReader : TextReader 
312         {
313             internal TextReader _in;
314             
315             internal SyncTextReader(TextReader t) 
316             {
317                 _in = t;        
318             }
319             
320             [MethodImplAttribute(MethodImplOptions.Synchronized)]
321             public override void Close() 
322             {
323                 // So that any overriden Close() gets run
324                 _in.Close();
325             }
326
327             [MethodImplAttribute(MethodImplOptions.Synchronized)]
328             protected override void Dispose(bool disposing) 
329             {
330                 // Explicitly pick up a potentially methodimpl'ed Dispose
331                 if (disposing)
332                     ((IDisposable)_in).Dispose();
333             }
334             
335             [MethodImplAttribute(MethodImplOptions.Synchronized)]
336             public override int Peek() 
337             {
338                 return _in.Peek();
339             }
340             
341             [MethodImplAttribute(MethodImplOptions.Synchronized)]
342             public override int Read() 
343             {
344                 return _in.Read();
345             }
346
347             [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
348             [MethodImplAttribute(MethodImplOptions.Synchronized)]
349             public override int Read([In, Out] char[] buffer, int index, int count) 
350             {
351                 return _in.Read(buffer, index, count);
352             }
353             
354             [MethodImplAttribute(MethodImplOptions.Synchronized)]
355             public override int ReadBlock([In, Out] char[] buffer, int index, int count) 
356             {
357                 return _in.ReadBlock(buffer, index, count);
358             }
359             
360             [MethodImplAttribute(MethodImplOptions.Synchronized)]
361             public override String ReadLine() 
362             {
363                 return _in.ReadLine();
364             }
365
366             [MethodImplAttribute(MethodImplOptions.Synchronized)]
367             public override String ReadToEnd() 
368             {
369                 return _in.ReadToEnd();
370             }
371 #if FEATURE_ASYNC_IO
372
373             //
374             // On SyncTextReader all APIs should run synchronously, even the async ones.
375             //
376
377             [ComVisible(false)]
378             [MethodImplAttribute(MethodImplOptions.Synchronized)]
379             public override Task<String> ReadLineAsync()
380             {
381                 return Task.FromResult(ReadLine());
382             }
383
384             [ComVisible(false)]
385             [MethodImplAttribute(MethodImplOptions.Synchronized)]
386             public override Task<String> ReadToEndAsync()
387             {
388                 return Task.FromResult(ReadToEnd());
389             }
390
391             [ComVisible(false)]
392             [MethodImplAttribute(MethodImplOptions.Synchronized)]
393             public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
394             {
395                 if (buffer==null)
396                     throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
397                 if (index < 0 || count < 0)
398                     throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
399                 if (buffer.Length - index < count)
400                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
401
402                 Contract.EndContractBlock();
403
404                 return Task.FromResult(ReadBlock(buffer, index, count));
405             }
406
407             [ComVisible(false)]
408             [MethodImplAttribute(MethodImplOptions.Synchronized)]
409             public override Task<int> ReadAsync(char[] buffer, int index, int count)
410             {
411                 if (buffer==null)
412                     throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
413                 if (index < 0 || count < 0)
414                     throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
415                 if (buffer.Length - index < count)
416                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
417                 Contract.EndContractBlock();
418
419                 return Task.FromResult(Read(buffer, index, count));
420             }
421 #endif //FEATURE_ASYNC_IO
422         }
423     }
424 }