3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>Microsoft</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.
42 #if FEATURE_REMOTING || MONO
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