3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
13 ** Purpose: Abstract base class for all Text-only Readers.
14 ** Subclasses will include StreamReader & StringReader.
17 ===========================================================*/
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;
28 using System.Threading;
29 using System.Threading.Tasks;
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.
38 // This class is intended for character input, not bytes.
39 // There are methods on the Stream class for reading bytes.
43 public abstract class TextReader : MarshalByRefObject, IDisposable {
44 #else // FEATURE_REMOTING
45 public abstract class TextReader : IDisposable {
46 #endif // FEATURE_REMOTING
50 private static Func<object, string> _ReadLineDelegate = state => ((TextReader)state).ReadLine();
53 private static Func<object, int> _ReadDelegate = state =>
55 Tuple<TextReader, char[], int, int> tuple = (Tuple<TextReader, char[], int, int>)state;
56 return tuple.Item1.Read(tuple.Item2, tuple.Item3, tuple.Item4);
58 #endif //FEATURE_ASYNC_IO
60 public static readonly TextReader Null = new NullTextReader();
62 protected TextReader() {}
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.
68 // This default method is empty, but descendant classes can override the
69 // method to provide the appropriate functionality.
70 public virtual void Close()
73 GC.SuppressFinalize(this);
79 GC.SuppressFinalize(this);
82 protected virtual void Dispose(bool disposing)
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
91 // This default method simply returns -1.
94 public virtual int Peek()
96 Contract.Ensures(Contract.Result<int>() >= -1);
101 // Reads the next character from the input stream. The returned value is
102 // -1 if no further characters are available.
104 // This default method simply returns -1.
106 public virtual int Read()
108 Contract.Ensures(Contract.Result<int>() >= -1);
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.
117 public virtual int Read([In, Out] char[] buffer, int index, int count)
120 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
122 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
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();
135 buffer[index + n++] = (char)ch;
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()
144 Contract.Ensures(Contract.Result<String>() != null);
146 char[] chars = new char[4096];
148 StringBuilder sb = new StringBuilder(4096);
149 while((len=Read(chars, 0, chars.Length)) != 0)
151 sb.Append(chars, 0, len);
153 return sb.ToString();
156 // Blocking version of read. Returns only when count
157 // characters have been read or the end of the file was reached.
159 public virtual int ReadBlock([In, Out] char[] buffer, int index, int count)
161 Contract.Ensures(Contract.Result<int>() >= 0);
162 Contract.Ensures(Contract.Result<int>() <= count);
166 n += (i = Read(buffer, index + n, count - n));
167 } while (i > 0 && n < count);
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.
177 public virtual String ReadLine()
179 StringBuilder sb = new StringBuilder();
183 if (ch == '\r' || ch == '\n')
185 if (ch == '\r' && Peek() == '\n') Read();
186 return sb.ToString();
190 if (sb.Length > 0) return sb.ToString();
195 #region Task based Async APIs
196 [HostProtection(ExternalThreading=true)]
198 public virtual Task<String> ReadLineAsync()
200 return Task<String>.Factory.StartNew(_ReadLineDelegate, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
203 [HostProtection(ExternalThreading=true)]
205 public async virtual Task<String> ReadToEndAsync()
207 char[] chars = new char[4096];
209 StringBuilder sb = new StringBuilder(4096);
210 while((len = await ReadAsyncInternal(chars, 0, chars.Length).ConfigureAwait(false)) != 0)
212 sb.Append(chars, 0, len);
214 return sb.ToString();
217 [HostProtection(ExternalThreading=true)]
219 public virtual Task<int> ReadAsync(char[] buffer, int index, int count)
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();
229 return ReadAsyncInternal(buffer, index, count);
232 internal virtual Task<int> ReadAsyncInternal(char[] buffer, int index, int count)
234 Contract.Requires(buffer != null);
235 Contract.Requires(index >= 0);
236 Contract.Requires(count >= 0);
237 Contract.Requires(buffer.Length - index >= count);
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);
243 [HostProtection(ExternalThreading=true)]
245 public virtual Task<int> ReadBlockAsync(char[] buffer, int index, int count)
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"));
254 Contract.EndContractBlock();
256 return ReadBlockAsyncInternal(buffer, index, count);
259 [HostProtection(ExternalThreading=true)]
260 private async Task<int> ReadBlockAsyncInternal(char[] buffer, int index, int count)
262 Contract.Requires(buffer != null);
263 Contract.Requires(index >= 0);
264 Contract.Requires(count >= 0);
265 Contract.Requires(buffer.Length - index >= count);
270 i = await ReadAsyncInternal(buffer, index + n, count - n).ConfigureAwait(false);
272 } while (i > 0 && n < count);
277 #endif //FEATURE_ASYNC_IO
279 [HostProtection(Synchronization=true)]
280 public static TextReader Synchronized(TextReader reader)
283 throw new ArgumentNullException("reader");
284 Contract.Ensures(Contract.Result<TextReader>() != null);
285 Contract.EndContractBlock();
287 if (reader is SyncTextReader)
290 return new SyncTextReader(reader);
294 private sealed class NullTextReader : TextReader
296 public NullTextReader(){}
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)
304 public override String ReadLine()
311 internal sealed class SyncTextReader : TextReader
313 internal TextReader _in;
315 internal SyncTextReader(TextReader t)
320 [MethodImplAttribute(MethodImplOptions.Synchronized)]
321 public override void Close()
323 // So that any overriden Close() gets run
327 [MethodImplAttribute(MethodImplOptions.Synchronized)]
328 protected override void Dispose(bool disposing)
330 // Explicitly pick up a potentially methodimpl'ed Dispose
332 ((IDisposable)_in).Dispose();
335 [MethodImplAttribute(MethodImplOptions.Synchronized)]
336 public override int Peek()
341 [MethodImplAttribute(MethodImplOptions.Synchronized)]
342 public override int Read()
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)
351 return _in.Read(buffer, index, count);
354 [MethodImplAttribute(MethodImplOptions.Synchronized)]
355 public override int ReadBlock([In, Out] char[] buffer, int index, int count)
357 return _in.ReadBlock(buffer, index, count);
360 [MethodImplAttribute(MethodImplOptions.Synchronized)]
361 public override String ReadLine()
363 return _in.ReadLine();
366 [MethodImplAttribute(MethodImplOptions.Synchronized)]
367 public override String ReadToEnd()
369 return _in.ReadToEnd();
374 // On SyncTextReader all APIs should run synchronously, even the async ones.
378 [MethodImplAttribute(MethodImplOptions.Synchronized)]
379 public override Task<String> ReadLineAsync()
381 return Task.FromResult(ReadLine());
385 [MethodImplAttribute(MethodImplOptions.Synchronized)]
386 public override Task<String> ReadToEndAsync()
388 return Task.FromResult(ReadToEnd());
392 [MethodImplAttribute(MethodImplOptions.Synchronized)]
393 public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
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"));
402 Contract.EndContractBlock();
404 return Task.FromResult(ReadBlock(buffer, index, count));
408 [MethodImplAttribute(MethodImplOptions.Synchronized)]
409 public override Task<int> ReadAsync(char[] buffer, int index, int count)
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();
419 return Task.FromResult(Read(buffer, index, count));
421 #endif //FEATURE_ASYNC_IO