StreamReader.cs 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Diagnostics.CodeAnalysis;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace System.IO
  11. {
  12. // This class implements a TextReader for reading characters to a Stream.
  13. // This is designed for character input in a particular Encoding,
  14. // whereas the Stream class is designed for byte input and output.
  15. public class StreamReader : TextReader
  16. {
  17. // StreamReader.Null is threadsafe.
  18. public new static readonly StreamReader Null = new NullStreamReader();
  19. // Using a 1K byte buffer and a 4K FileStream buffer works out pretty well
  20. // perf-wise. On even a 40 MB text file, any perf loss by using a 4K
  21. // buffer is negated by the win of allocating a smaller byte[], which
  22. // saves construction time. This does break adaptive buffering,
  23. // but this is slightly faster.
  24. private const int DefaultBufferSize = 1024; // Byte buffer size
  25. private const int DefaultFileStreamBufferSize = 4096;
  26. private const int MinBufferSize = 128;
  27. private Stream _stream;
  28. private Encoding _encoding;
  29. private Decoder _decoder;
  30. private byte[] _byteBuffer;
  31. private char[] _charBuffer;
  32. private int _charPos;
  33. private int _charLen;
  34. // Record the number of valid bytes in the byteBuffer, for a few checks.
  35. private int _byteLen;
  36. // This is used only for preamble detection
  37. private int _bytePos;
  38. // This is the maximum number of chars we can get from one call to
  39. // ReadBuffer. Used so ReadBuffer can tell when to copy data into
  40. // a user's char[] directly, instead of our internal char[].
  41. private int _maxCharsPerBuffer;
  42. // We will support looking for byte order marks in the stream and trying
  43. // to decide what the encoding might be from the byte order marks, IF they
  44. // exist. But that's all we'll do.
  45. private bool _detectEncoding;
  46. // Whether we must still check for the encoding's given preamble at the
  47. // beginning of this file.
  48. private bool _checkPreamble;
  49. // Whether the stream is most likely not going to give us back as much
  50. // data as we want the next time we call it. We must do the computation
  51. // before we do any byte order mark handling and save the result. Note
  52. // that we need this to allow users to handle streams used for an
  53. // interactive protocol, where they block waiting for the remote end
  54. // to send a response, like logging in on a Unix machine.
  55. private bool _isBlocked;
  56. // The intent of this field is to leave open the underlying stream when
  57. // disposing of this StreamReader. A name like _leaveOpen is better,
  58. // but this type is serializable, and this field's name was _closable.
  59. private bool _closable; // Whether to close the underlying stream.
  60. // We don't guarantee thread safety on StreamReader, but we should at
  61. // least prevent users from trying to read anything while an Async
  62. // read from the same thread is in progress.
  63. private Task _asyncReadTask = Task.CompletedTask;
  64. private void CheckAsyncTaskInProgress()
  65. {
  66. // We are not locking the access to _asyncReadTask because this is not meant to guarantee thread safety.
  67. // We are simply trying to deter calling any Read APIs while an async Read from the same thread is in progress.
  68. if (!_asyncReadTask.IsCompleted)
  69. {
  70. ThrowAsyncIOInProgress();
  71. }
  72. }
  73. private static void ThrowAsyncIOInProgress() =>
  74. throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
  75. // StreamReader by default will ignore illegal UTF8 characters. We don't want to
  76. // throw here because we want to be able to read ill-formed data without choking.
  77. // The high level goal is to be tolerant of encoding errors when we read and very strict
  78. // when we write. Hence, default StreamWriter encoding will throw on error.
  79. internal StreamReader()
  80. {
  81. }
  82. public StreamReader(Stream stream)
  83. : this(stream, true)
  84. {
  85. }
  86. public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
  87. : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize, false)
  88. {
  89. }
  90. public StreamReader(Stream stream, Encoding encoding)
  91. : this(stream, encoding, true, DefaultBufferSize, false)
  92. {
  93. }
  94. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  95. : this(stream, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize, false)
  96. {
  97. }
  98. // Creates a new StreamReader for the given stream. The
  99. // character encoding is set by encoding and the buffer size,
  100. // in number of 16-bit characters, is set by bufferSize.
  101. //
  102. // Note that detectEncodingFromByteOrderMarks is a very
  103. // loose attempt at detecting the encoding by looking at the first
  104. // 3 bytes of the stream. It will recognize UTF-8, little endian
  105. // unicode, and big endian unicode text, but that's it. If neither
  106. // of those three match, it will use the Encoding you provided.
  107. //
  108. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  109. : this(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, false)
  110. {
  111. }
  112. public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen)
  113. {
  114. if (stream == null || encoding == null)
  115. {
  116. throw new ArgumentNullException(stream == null ? nameof(stream) : nameof(encoding));
  117. }
  118. if (!stream.CanRead)
  119. {
  120. throw new ArgumentException(SR.Argument_StreamNotReadable);
  121. }
  122. if (bufferSize <= 0)
  123. {
  124. throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum);
  125. }
  126. Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, leaveOpen);
  127. }
  128. public StreamReader(string path)
  129. : this(path, true)
  130. {
  131. }
  132. public StreamReader(string path, bool detectEncodingFromByteOrderMarks)
  133. : this(path, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize)
  134. {
  135. }
  136. public StreamReader(string path, Encoding encoding)
  137. : this(path, encoding, true, DefaultBufferSize)
  138. {
  139. }
  140. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  141. : this(path, encoding, detectEncodingFromByteOrderMarks, DefaultBufferSize)
  142. {
  143. }
  144. public StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
  145. {
  146. if (path == null)
  147. throw new ArgumentNullException(nameof(path));
  148. if (encoding == null)
  149. throw new ArgumentNullException(nameof(encoding));
  150. if (path.Length == 0)
  151. throw new ArgumentException(SR.Argument_EmptyPath);
  152. if (bufferSize <= 0)
  153. throw new ArgumentOutOfRangeException(nameof(bufferSize), SR.ArgumentOutOfRange_NeedPosNum);
  154. Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,
  155. DefaultFileStreamBufferSize, FileOptions.SequentialScan);
  156. Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize, leaveOpen: false);
  157. }
  158. private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen)
  159. {
  160. _stream = stream;
  161. _encoding = encoding;
  162. _decoder = encoding.GetDecoder();
  163. if (bufferSize < MinBufferSize)
  164. {
  165. bufferSize = MinBufferSize;
  166. }
  167. _byteBuffer = new byte[bufferSize];
  168. _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
  169. _charBuffer = new char[_maxCharsPerBuffer];
  170. _byteLen = 0;
  171. _bytePos = 0;
  172. _detectEncoding = detectEncodingFromByteOrderMarks;
  173. _checkPreamble = encoding.Preamble.Length > 0;
  174. _isBlocked = false;
  175. _closable = !leaveOpen;
  176. }
  177. // Init used by NullStreamReader, to delay load encoding
  178. internal void Init(Stream stream)
  179. {
  180. _stream = stream;
  181. _closable = true;
  182. }
  183. public override void Close()
  184. {
  185. Dispose(true);
  186. }
  187. protected override void Dispose(bool disposing)
  188. {
  189. // Dispose of our resources if this StreamReader is closable.
  190. // Note that Console.In should be left open.
  191. try
  192. {
  193. // Note that Stream.Close() can potentially throw here. So we need to
  194. // ensure cleaning up internal resources, inside the finally block.
  195. if (!LeaveOpen && disposing && (_stream != null))
  196. {
  197. _stream.Close();
  198. }
  199. }
  200. finally
  201. {
  202. if (!LeaveOpen && (_stream != null))
  203. {
  204. _stream = null;
  205. _encoding = null;
  206. _decoder = null;
  207. _byteBuffer = null;
  208. _charBuffer = null;
  209. _charPos = 0;
  210. _charLen = 0;
  211. base.Dispose(disposing);
  212. }
  213. }
  214. }
  215. public virtual Encoding CurrentEncoding
  216. {
  217. get { return _encoding; }
  218. }
  219. public virtual Stream BaseStream
  220. {
  221. get { return _stream; }
  222. }
  223. internal bool LeaveOpen
  224. {
  225. get { return !_closable; }
  226. }
  227. // DiscardBufferedData tells StreamReader to throw away its internal
  228. // buffer contents. This is useful if the user needs to seek on the
  229. // underlying stream to a known location then wants the StreamReader
  230. // to start reading from this new point. This method should be called
  231. // very sparingly, if ever, since it can lead to very poor performance.
  232. // However, it may be the only way of handling some scenarios where
  233. // users need to re-read the contents of a StreamReader a second time.
  234. public void DiscardBufferedData()
  235. {
  236. CheckAsyncTaskInProgress();
  237. _byteLen = 0;
  238. _charLen = 0;
  239. _charPos = 0;
  240. // in general we'd like to have an invariant that encoding isn't null. However,
  241. // for startup improvements for NullStreamReader, we want to delay load encoding.
  242. if (_encoding != null)
  243. {
  244. _decoder = _encoding.GetDecoder();
  245. }
  246. _isBlocked = false;
  247. }
  248. public bool EndOfStream
  249. {
  250. get
  251. {
  252. if (_stream == null)
  253. {
  254. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  255. }
  256. CheckAsyncTaskInProgress();
  257. if (_charPos < _charLen)
  258. {
  259. return false;
  260. }
  261. // This may block on pipes!
  262. int numRead = ReadBuffer();
  263. return numRead == 0;
  264. }
  265. }
  266. public override int Peek()
  267. {
  268. if (_stream == null)
  269. {
  270. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  271. }
  272. CheckAsyncTaskInProgress();
  273. if (_charPos == _charLen)
  274. {
  275. if (_isBlocked || ReadBuffer() == 0)
  276. {
  277. return -1;
  278. }
  279. }
  280. return _charBuffer[_charPos];
  281. }
  282. public override int Read()
  283. {
  284. if (_stream == null)
  285. {
  286. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  287. }
  288. CheckAsyncTaskInProgress();
  289. if (_charPos == _charLen)
  290. {
  291. if (ReadBuffer() == 0)
  292. {
  293. return -1;
  294. }
  295. }
  296. int result = _charBuffer[_charPos];
  297. _charPos++;
  298. return result;
  299. }
  300. public override int Read(char[] buffer, int index, int count)
  301. {
  302. if (buffer == null)
  303. {
  304. throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
  305. }
  306. if (index < 0 || count < 0)
  307. {
  308. throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  309. }
  310. if (buffer.Length - index < count)
  311. {
  312. throw new ArgumentException(SR.Argument_InvalidOffLen);
  313. }
  314. return ReadSpan(new Span<char>(buffer, index, count));
  315. }
  316. public override int Read(Span<char> buffer) =>
  317. GetType() == typeof(StreamReader) ? ReadSpan(buffer) :
  318. base.Read(buffer); // Defer to Read(char[], ...) if a derived type may have previously overridden it
  319. private int ReadSpan(Span<char> buffer)
  320. {
  321. if (_stream == null)
  322. {
  323. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  324. }
  325. CheckAsyncTaskInProgress();
  326. int charsRead = 0;
  327. // As a perf optimization, if we had exactly one buffer's worth of
  328. // data read in, let's try writing directly to the user's buffer.
  329. bool readToUserBuffer = false;
  330. int count = buffer.Length;
  331. while (count > 0)
  332. {
  333. int n = _charLen - _charPos;
  334. if (n == 0)
  335. {
  336. n = ReadBuffer(buffer.Slice(charsRead), out readToUserBuffer);
  337. }
  338. if (n == 0)
  339. {
  340. break; // We're at EOF
  341. }
  342. if (n > count)
  343. {
  344. n = count;
  345. }
  346. if (!readToUserBuffer)
  347. {
  348. new Span<char>(_charBuffer, _charPos, n).CopyTo(buffer.Slice(charsRead));
  349. _charPos += n;
  350. }
  351. charsRead += n;
  352. count -= n;
  353. // This function shouldn't block for an indefinite amount of time,
  354. // or reading from a network stream won't work right. If we got
  355. // fewer bytes than we requested, then we want to break right here.
  356. if (_isBlocked)
  357. {
  358. break;
  359. }
  360. }
  361. return charsRead;
  362. }
  363. public override string ReadToEnd()
  364. {
  365. if (_stream == null)
  366. {
  367. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  368. }
  369. CheckAsyncTaskInProgress();
  370. // Call ReadBuffer, then pull data out of charBuffer.
  371. StringBuilder sb = new StringBuilder(_charLen - _charPos);
  372. do
  373. {
  374. sb.Append(_charBuffer, _charPos, _charLen - _charPos);
  375. _charPos = _charLen; // Note we consumed these characters
  376. ReadBuffer();
  377. } while (_charLen > 0);
  378. return sb.ToString();
  379. }
  380. public override int ReadBlock(char[] buffer, int index, int count)
  381. {
  382. if (buffer == null)
  383. {
  384. throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
  385. }
  386. if (index < 0 || count < 0)
  387. {
  388. throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  389. }
  390. if (buffer.Length - index < count)
  391. {
  392. throw new ArgumentException(SR.Argument_InvalidOffLen);
  393. }
  394. if (_stream == null)
  395. {
  396. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  397. }
  398. CheckAsyncTaskInProgress();
  399. return base.ReadBlock(buffer, index, count);
  400. }
  401. public override int ReadBlock(Span<char> buffer)
  402. {
  403. if (GetType() != typeof(StreamReader))
  404. {
  405. // Defer to Read(char[], ...) if a derived type may have previously overridden it.
  406. return base.ReadBlock(buffer);
  407. }
  408. int i, n = 0;
  409. do
  410. {
  411. i = ReadSpan(buffer.Slice(n));
  412. n += i;
  413. } while (i > 0 && n < buffer.Length);
  414. return n;
  415. }
  416. // Trims n bytes from the front of the buffer.
  417. private void CompressBuffer(int n)
  418. {
  419. Debug.Assert(_byteLen >= n, "CompressBuffer was called with a number of bytes greater than the current buffer length. Are two threads using this StreamReader at the same time?");
  420. Buffer.BlockCopy(_byteBuffer, n, _byteBuffer, 0, _byteLen - n);
  421. _byteLen -= n;
  422. }
  423. private void DetectEncoding()
  424. {
  425. if (_byteLen < 2)
  426. {
  427. return;
  428. }
  429. _detectEncoding = false;
  430. bool changedEncoding = false;
  431. if (_byteBuffer[0] == 0xFE && _byteBuffer[1] == 0xFF)
  432. {
  433. // Big Endian Unicode
  434. _encoding = Encoding.BigEndianUnicode;
  435. CompressBuffer(2);
  436. changedEncoding = true;
  437. }
  438. else if (_byteBuffer[0] == 0xFF && _byteBuffer[1] == 0xFE)
  439. {
  440. // Little Endian Unicode, or possibly little endian UTF32
  441. if (_byteLen < 4 || _byteBuffer[2] != 0 || _byteBuffer[3] != 0)
  442. {
  443. _encoding = Encoding.Unicode;
  444. CompressBuffer(2);
  445. changedEncoding = true;
  446. }
  447. else
  448. {
  449. _encoding = Encoding.UTF32;
  450. CompressBuffer(4);
  451. changedEncoding = true;
  452. }
  453. }
  454. else if (_byteLen >= 3 && _byteBuffer[0] == 0xEF && _byteBuffer[1] == 0xBB && _byteBuffer[2] == 0xBF)
  455. {
  456. // UTF-8
  457. _encoding = Encoding.UTF8;
  458. CompressBuffer(3);
  459. changedEncoding = true;
  460. }
  461. else if (_byteLen >= 4 && _byteBuffer[0] == 0 && _byteBuffer[1] == 0 &&
  462. _byteBuffer[2] == 0xFE && _byteBuffer[3] == 0xFF)
  463. {
  464. // Big Endian UTF32
  465. _encoding = new UTF32Encoding(bigEndian: true, byteOrderMark: true);
  466. CompressBuffer(4);
  467. changedEncoding = true;
  468. }
  469. else if (_byteLen == 2)
  470. {
  471. _detectEncoding = true;
  472. }
  473. // Note: in the future, if we change this algorithm significantly,
  474. // we can support checking for the preamble of the given encoding.
  475. if (changedEncoding)
  476. {
  477. _decoder = _encoding.GetDecoder();
  478. int newMaxCharsPerBuffer = _encoding.GetMaxCharCount(_byteBuffer.Length);
  479. if (newMaxCharsPerBuffer > _maxCharsPerBuffer)
  480. {
  481. _charBuffer = new char[newMaxCharsPerBuffer];
  482. }
  483. _maxCharsPerBuffer = newMaxCharsPerBuffer;
  484. }
  485. }
  486. // Trims the preamble bytes from the byteBuffer. This routine can be called multiple times
  487. // and we will buffer the bytes read until the preamble is matched or we determine that
  488. // there is no match. If there is no match, every byte read previously will be available
  489. // for further consumption. If there is a match, we will compress the buffer for the
  490. // leading preamble bytes
  491. private bool IsPreamble()
  492. {
  493. if (!_checkPreamble)
  494. {
  495. return _checkPreamble;
  496. }
  497. ReadOnlySpan<byte> preamble = _encoding.Preamble;
  498. Debug.Assert(_bytePos <= preamble.Length, "_compressPreamble was called with the current bytePos greater than the preamble buffer length. Are two threads using this StreamReader at the same time?");
  499. int len = (_byteLen >= (preamble.Length)) ? (preamble.Length - _bytePos) : (_byteLen - _bytePos);
  500. for (int i = 0; i < len; i++, _bytePos++)
  501. {
  502. if (_byteBuffer[_bytePos] != preamble[_bytePos])
  503. {
  504. _bytePos = 0;
  505. _checkPreamble = false;
  506. break;
  507. }
  508. }
  509. Debug.Assert(_bytePos <= preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
  510. if (_checkPreamble)
  511. {
  512. if (_bytePos == preamble.Length)
  513. {
  514. // We have a match
  515. CompressBuffer(preamble.Length);
  516. _bytePos = 0;
  517. _checkPreamble = false;
  518. _detectEncoding = false;
  519. }
  520. }
  521. return _checkPreamble;
  522. }
  523. internal virtual int ReadBuffer()
  524. {
  525. _charLen = 0;
  526. _charPos = 0;
  527. if (!_checkPreamble)
  528. {
  529. _byteLen = 0;
  530. }
  531. do
  532. {
  533. if (_checkPreamble)
  534. {
  535. Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
  536. int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos);
  537. Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  538. if (len == 0)
  539. {
  540. // EOF but we might have buffered bytes from previous
  541. // attempt to detect preamble that needs to be decoded now
  542. if (_byteLen > 0)
  543. {
  544. _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen);
  545. // Need to zero out the byteLen after we consume these bytes so that we don't keep infinitely hitting this code path
  546. _bytePos = _byteLen = 0;
  547. }
  548. return _charLen;
  549. }
  550. _byteLen += len;
  551. }
  552. else
  553. {
  554. Debug.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
  555. _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length);
  556. Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  557. if (_byteLen == 0) // We're at EOF
  558. {
  559. return _charLen;
  560. }
  561. }
  562. // _isBlocked == whether we read fewer bytes than we asked for.
  563. // Note we must check it here because CompressBuffer or
  564. // DetectEncoding will change byteLen.
  565. _isBlocked = (_byteLen < _byteBuffer.Length);
  566. // Check for preamble before detect encoding. This is not to override the
  567. // user supplied Encoding for the one we implicitly detect. The user could
  568. // customize the encoding which we will loose, such as ThrowOnError on UTF8
  569. if (IsPreamble())
  570. {
  571. continue;
  572. }
  573. // If we're supposed to detect the encoding and haven't done so yet,
  574. // do it. Note this may need to be called more than once.
  575. if (_detectEncoding && _byteLen >= 2)
  576. {
  577. DetectEncoding();
  578. }
  579. _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen);
  580. } while (_charLen == 0);
  581. //Console.WriteLine("ReadBuffer called. chars: "+charLen);
  582. return _charLen;
  583. }
  584. // This version has a perf optimization to decode data DIRECTLY into the
  585. // user's buffer, bypassing StreamReader's own buffer.
  586. // This gives a > 20% perf improvement for our encodings across the board,
  587. // but only when asking for at least the number of characters that one
  588. // buffer's worth of bytes could produce.
  589. // This optimization, if run, will break SwitchEncoding, so we must not do
  590. // this on the first call to ReadBuffer.
  591. private int ReadBuffer(Span<char> userBuffer, out bool readToUserBuffer)
  592. {
  593. _charLen = 0;
  594. _charPos = 0;
  595. if (!_checkPreamble)
  596. {
  597. _byteLen = 0;
  598. }
  599. int charsRead = 0;
  600. // As a perf optimization, we can decode characters DIRECTLY into a
  601. // user's char[]. We absolutely must not write more characters
  602. // into the user's buffer than they asked for. Calculating
  603. // encoding.GetMaxCharCount(byteLen) each time is potentially very
  604. // expensive - instead, cache the number of chars a full buffer's
  605. // worth of data may produce. Yes, this makes the perf optimization
  606. // less aggressive, in that all reads that asked for fewer than AND
  607. // returned fewer than _maxCharsPerBuffer chars won't get the user
  608. // buffer optimization. This affects reads where the end of the
  609. // Stream comes in the middle somewhere, and when you ask for
  610. // fewer chars than your buffer could produce.
  611. readToUserBuffer = userBuffer.Length >= _maxCharsPerBuffer;
  612. do
  613. {
  614. Debug.Assert(charsRead == 0);
  615. if (_checkPreamble)
  616. {
  617. Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
  618. int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos);
  619. Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  620. if (len == 0)
  621. {
  622. // EOF but we might have buffered bytes from previous
  623. // attempt to detect preamble that needs to be decoded now
  624. if (_byteLen > 0)
  625. {
  626. if (readToUserBuffer)
  627. {
  628. charsRead = _decoder.GetChars(new ReadOnlySpan<byte>(_byteBuffer, 0, _byteLen), userBuffer.Slice(charsRead), flush: false);
  629. _charLen = 0; // StreamReader's buffer is empty.
  630. }
  631. else
  632. {
  633. charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead);
  634. _charLen += charsRead; // Number of chars in StreamReader's buffer.
  635. }
  636. }
  637. return charsRead;
  638. }
  639. _byteLen += len;
  640. }
  641. else
  642. {
  643. Debug.Assert(_bytePos == 0, "bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
  644. _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length);
  645. Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  646. if (_byteLen == 0) // EOF
  647. {
  648. break;
  649. }
  650. }
  651. // _isBlocked == whether we read fewer bytes than we asked for.
  652. // Note we must check it here because CompressBuffer or
  653. // DetectEncoding will change byteLen.
  654. _isBlocked = (_byteLen < _byteBuffer.Length);
  655. // Check for preamble before detect encoding. This is not to override the
  656. // user supplied Encoding for the one we implicitly detect. The user could
  657. // customize the encoding which we will loose, such as ThrowOnError on UTF8
  658. // Note: we don't need to recompute readToUserBuffer optimization as IsPreamble
  659. // doesn't change the encoding or affect _maxCharsPerBuffer
  660. if (IsPreamble())
  661. {
  662. continue;
  663. }
  664. // On the first call to ReadBuffer, if we're supposed to detect the encoding, do it.
  665. if (_detectEncoding && _byteLen >= 2)
  666. {
  667. DetectEncoding();
  668. // DetectEncoding changes some buffer state. Recompute this.
  669. readToUserBuffer = userBuffer.Length >= _maxCharsPerBuffer;
  670. }
  671. _charPos = 0;
  672. if (readToUserBuffer)
  673. {
  674. charsRead += _decoder.GetChars(new ReadOnlySpan<byte>(_byteBuffer, 0, _byteLen), userBuffer.Slice(charsRead), flush:false);
  675. _charLen = 0; // StreamReader's buffer is empty.
  676. }
  677. else
  678. {
  679. charsRead = _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, charsRead);
  680. _charLen += charsRead; // Number of chars in StreamReader's buffer.
  681. }
  682. } while (charsRead == 0);
  683. _isBlocked &= charsRead < userBuffer.Length;
  684. //Console.WriteLine("ReadBuffer: charsRead: "+charsRead+" readToUserBuffer: "+readToUserBuffer);
  685. return charsRead;
  686. }
  687. // Reads a line. A line is defined as a sequence of characters followed by
  688. // a carriage return ('\r'), a line feed ('\n'), or a carriage return
  689. // immediately followed by a line feed. The resulting string does not
  690. // contain the terminating carriage return and/or line feed. The returned
  691. // value is null if the end of the input stream has been reached.
  692. //
  693. public override string ReadLine()
  694. {
  695. if (_stream == null)
  696. {
  697. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  698. }
  699. CheckAsyncTaskInProgress();
  700. if (_charPos == _charLen)
  701. {
  702. if (ReadBuffer() == 0)
  703. {
  704. return null;
  705. }
  706. }
  707. StringBuilder sb = null;
  708. do
  709. {
  710. int i = _charPos;
  711. do
  712. {
  713. char ch = _charBuffer[i];
  714. // Note the following common line feed chars:
  715. // \n - UNIX \r\n - DOS \r - Mac
  716. if (ch == '\r' || ch == '\n')
  717. {
  718. string s;
  719. if (sb != null)
  720. {
  721. sb.Append(_charBuffer, _charPos, i - _charPos);
  722. s = sb.ToString();
  723. }
  724. else
  725. {
  726. s = new string(_charBuffer, _charPos, i - _charPos);
  727. }
  728. _charPos = i + 1;
  729. if (ch == '\r' && (_charPos < _charLen || ReadBuffer() > 0))
  730. {
  731. if (_charBuffer[_charPos] == '\n')
  732. {
  733. _charPos++;
  734. }
  735. }
  736. return s;
  737. }
  738. i++;
  739. } while (i < _charLen);
  740. i = _charLen - _charPos;
  741. if (sb == null)
  742. {
  743. sb = new StringBuilder(i + 80);
  744. }
  745. sb.Append(_charBuffer, _charPos, i);
  746. } while (ReadBuffer() > 0);
  747. return sb.ToString();
  748. }
  749. #region Task based Async APIs
  750. public override Task<string> ReadLineAsync()
  751. {
  752. // If we have been inherited into a subclass, the following implementation could be incorrect
  753. // since it does not call through to Read() which a subclass might have overridden.
  754. // To be safe we will only use this implementation in cases where we know it is safe to do so,
  755. // and delegate to our base class (which will call into Read) when we are not sure.
  756. if (GetType() != typeof(StreamReader))
  757. {
  758. return base.ReadLineAsync();
  759. }
  760. if (_stream == null)
  761. {
  762. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  763. }
  764. CheckAsyncTaskInProgress();
  765. Task<string> task = ReadLineAsyncInternal();
  766. _asyncReadTask = task;
  767. return task;
  768. }
  769. private async Task<string> ReadLineAsyncInternal()
  770. {
  771. if (_charPos == _charLen && (await ReadBufferAsync().ConfigureAwait(false)) == 0)
  772. {
  773. return null;
  774. }
  775. StringBuilder sb = null;
  776. do
  777. {
  778. char[] tmpCharBuffer = _charBuffer;
  779. int tmpCharLen = _charLen;
  780. int tmpCharPos = _charPos;
  781. int i = tmpCharPos;
  782. do
  783. {
  784. char ch = tmpCharBuffer[i];
  785. // Note the following common line feed chars:
  786. // \n - UNIX \r\n - DOS \r - Mac
  787. if (ch == '\r' || ch == '\n')
  788. {
  789. string s;
  790. if (sb != null)
  791. {
  792. sb.Append(tmpCharBuffer, tmpCharPos, i - tmpCharPos);
  793. s = sb.ToString();
  794. }
  795. else
  796. {
  797. s = new string(tmpCharBuffer, tmpCharPos, i - tmpCharPos);
  798. }
  799. _charPos = tmpCharPos = i + 1;
  800. if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync().ConfigureAwait(false)) > 0))
  801. {
  802. tmpCharPos = _charPos;
  803. if (_charBuffer[tmpCharPos] == '\n')
  804. {
  805. _charPos = ++tmpCharPos;
  806. }
  807. }
  808. return s;
  809. }
  810. i++;
  811. } while (i < tmpCharLen);
  812. i = tmpCharLen - tmpCharPos;
  813. if (sb == null)
  814. {
  815. sb = new StringBuilder(i + 80);
  816. }
  817. sb.Append(tmpCharBuffer, tmpCharPos, i);
  818. } while (await ReadBufferAsync().ConfigureAwait(false) > 0);
  819. return sb.ToString();
  820. }
  821. public override Task<string> ReadToEndAsync()
  822. {
  823. // If we have been inherited into a subclass, the following implementation could be incorrect
  824. // since it does not call through to Read() which a subclass might have overridden.
  825. // To be safe we will only use this implementation in cases where we know it is safe to do so,
  826. // and delegate to our base class (which will call into Read) when we are not sure.
  827. if (GetType() != typeof(StreamReader))
  828. {
  829. return base.ReadToEndAsync();
  830. }
  831. if (_stream == null)
  832. {
  833. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  834. }
  835. CheckAsyncTaskInProgress();
  836. Task<string> task = ReadToEndAsyncInternal();
  837. _asyncReadTask = task;
  838. return task;
  839. }
  840. private async Task<string> ReadToEndAsyncInternal()
  841. {
  842. // Call ReadBuffer, then pull data out of charBuffer.
  843. StringBuilder sb = new StringBuilder(_charLen - _charPos);
  844. do
  845. {
  846. int tmpCharPos = _charPos;
  847. sb.Append(_charBuffer, tmpCharPos, _charLen - tmpCharPos);
  848. _charPos = _charLen; // We consumed these characters
  849. await ReadBufferAsync().ConfigureAwait(false);
  850. } while (_charLen > 0);
  851. return sb.ToString();
  852. }
  853. public override Task<int> ReadAsync(char[] buffer, int index, int count)
  854. {
  855. if (buffer == null)
  856. {
  857. throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
  858. }
  859. if (index < 0 || count < 0)
  860. {
  861. throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  862. }
  863. if (buffer.Length - index < count)
  864. {
  865. throw new ArgumentException(SR.Argument_InvalidOffLen);
  866. }
  867. // If we have been inherited into a subclass, the following implementation could be incorrect
  868. // since it does not call through to Read() which a subclass might have overridden.
  869. // To be safe we will only use this implementation in cases where we know it is safe to do so,
  870. // and delegate to our base class (which will call into Read) when we are not sure.
  871. if (GetType() != typeof(StreamReader))
  872. {
  873. return base.ReadAsync(buffer, index, count);
  874. }
  875. if (_stream == null)
  876. {
  877. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  878. }
  879. CheckAsyncTaskInProgress();
  880. Task<int> task = ReadAsyncInternal(new Memory<char>(buffer, index, count), default).AsTask();
  881. _asyncReadTask = task;
  882. return task;
  883. }
  884. public override ValueTask<int> ReadAsync(Memory<char> buffer, CancellationToken cancellationToken = default)
  885. {
  886. if (GetType() != typeof(StreamReader))
  887. {
  888. // Ensure we use existing overrides if a class already overrode existing overloads.
  889. return base.ReadAsync(buffer, cancellationToken);
  890. }
  891. if (_stream == null)
  892. {
  893. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  894. }
  895. CheckAsyncTaskInProgress();
  896. if (cancellationToken.IsCancellationRequested)
  897. {
  898. return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
  899. }
  900. return ReadAsyncInternal(buffer, cancellationToken);
  901. }
  902. internal override async ValueTask<int> ReadAsyncInternal(Memory<char> buffer, CancellationToken cancellationToken)
  903. {
  904. if (_charPos == _charLen && (await ReadBufferAsync().ConfigureAwait(false)) == 0)
  905. {
  906. return 0;
  907. }
  908. int charsRead = 0;
  909. // As a perf optimization, if we had exactly one buffer's worth of
  910. // data read in, let's try writing directly to the user's buffer.
  911. bool readToUserBuffer = false;
  912. byte[] tmpByteBuffer = _byteBuffer;
  913. Stream tmpStream = _stream;
  914. int count = buffer.Length;
  915. while (count > 0)
  916. {
  917. // n is the characters available in _charBuffer
  918. int n = _charLen - _charPos;
  919. // charBuffer is empty, let's read from the stream
  920. if (n == 0)
  921. {
  922. _charLen = 0;
  923. _charPos = 0;
  924. if (!_checkPreamble)
  925. {
  926. _byteLen = 0;
  927. }
  928. readToUserBuffer = count >= _maxCharsPerBuffer;
  929. // We loop here so that we read in enough bytes to yield at least 1 char.
  930. // We break out of the loop if the stream is blocked (EOF is reached).
  931. do
  932. {
  933. Debug.Assert(n == 0);
  934. if (_checkPreamble)
  935. {
  936. Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
  937. int tmpBytePos = _bytePos;
  938. int len = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos), cancellationToken).ConfigureAwait(false);
  939. Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  940. if (len == 0)
  941. {
  942. // EOF but we might have buffered bytes from previous
  943. // attempts to detect preamble that needs to be decoded now
  944. if (_byteLen > 0)
  945. {
  946. if (readToUserBuffer)
  947. {
  948. n = _decoder.GetChars(new ReadOnlySpan<byte>(tmpByteBuffer, 0, _byteLen), buffer.Span.Slice(charsRead), flush: false);
  949. _charLen = 0; // StreamReader's buffer is empty.
  950. }
  951. else
  952. {
  953. n = _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, 0);
  954. _charLen += n; // Number of chars in StreamReader's buffer.
  955. }
  956. }
  957. // How can part of the preamble yield any chars?
  958. Debug.Assert(n == 0);
  959. _isBlocked = true;
  960. break;
  961. }
  962. else
  963. {
  964. _byteLen += len;
  965. }
  966. }
  967. else
  968. {
  969. Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
  970. _byteLen = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer), cancellationToken).ConfigureAwait(false);
  971. Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  972. if (_byteLen == 0) // EOF
  973. {
  974. _isBlocked = true;
  975. break;
  976. }
  977. }
  978. // _isBlocked == whether we read fewer bytes than we asked for.
  979. // Note we must check it here because CompressBuffer or
  980. // DetectEncoding will change _byteLen.
  981. _isBlocked = (_byteLen < tmpByteBuffer.Length);
  982. // Check for preamble before detect encoding. This is not to override the
  983. // user supplied Encoding for the one we implicitly detect. The user could
  984. // customize the encoding which we will loose, such as ThrowOnError on UTF8
  985. // Note: we don't need to recompute readToUserBuffer optimization as IsPreamble
  986. // doesn't change the encoding or affect _maxCharsPerBuffer
  987. if (IsPreamble())
  988. {
  989. continue;
  990. }
  991. // On the first call to ReadBuffer, if we're supposed to detect the encoding, do it.
  992. if (_detectEncoding && _byteLen >= 2)
  993. {
  994. DetectEncoding();
  995. // DetectEncoding changes some buffer state. Recompute this.
  996. readToUserBuffer = count >= _maxCharsPerBuffer;
  997. }
  998. Debug.Assert(n == 0);
  999. _charPos = 0;
  1000. if (readToUserBuffer)
  1001. {
  1002. n += _decoder.GetChars(new ReadOnlySpan<byte>(tmpByteBuffer, 0, _byteLen), buffer.Span.Slice(charsRead), flush: false);
  1003. // Why did the bytes yield no chars?
  1004. Debug.Assert(n > 0);
  1005. _charLen = 0; // StreamReader's buffer is empty.
  1006. }
  1007. else
  1008. {
  1009. n = _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, 0);
  1010. // Why did the bytes yield no chars?
  1011. Debug.Assert(n > 0);
  1012. _charLen += n; // Number of chars in StreamReader's buffer.
  1013. }
  1014. } while (n == 0);
  1015. if (n == 0)
  1016. {
  1017. break; // We're at EOF
  1018. }
  1019. } // if (n == 0)
  1020. // Got more chars in charBuffer than the user requested
  1021. if (n > count)
  1022. {
  1023. n = count;
  1024. }
  1025. if (!readToUserBuffer)
  1026. {
  1027. new Span<char>(_charBuffer, _charPos, n).CopyTo(buffer.Span.Slice(charsRead));
  1028. _charPos += n;
  1029. }
  1030. charsRead += n;
  1031. count -= n;
  1032. // This function shouldn't block for an indefinite amount of time,
  1033. // or reading from a network stream won't work right. If we got
  1034. // fewer bytes than we requested, then we want to break right here.
  1035. if (_isBlocked)
  1036. {
  1037. break;
  1038. }
  1039. } // while (count > 0)
  1040. return charsRead;
  1041. }
  1042. public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
  1043. {
  1044. if (buffer == null)
  1045. {
  1046. throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
  1047. }
  1048. if (index < 0 || count < 0)
  1049. {
  1050. throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  1051. }
  1052. if (buffer.Length - index < count)
  1053. {
  1054. throw new ArgumentException(SR.Argument_InvalidOffLen);
  1055. }
  1056. // If we have been inherited into a subclass, the following implementation could be incorrect
  1057. // since it does not call through to Read() which a subclass might have overridden.
  1058. // To be safe we will only use this implementation in cases where we know it is safe to do so,
  1059. // and delegate to our base class (which will call into Read) when we are not sure.
  1060. if (GetType() != typeof(StreamReader))
  1061. {
  1062. return base.ReadBlockAsync(buffer, index, count);
  1063. }
  1064. if (_stream == null)
  1065. {
  1066. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  1067. }
  1068. CheckAsyncTaskInProgress();
  1069. Task<int> task = base.ReadBlockAsync(buffer, index, count);
  1070. _asyncReadTask = task;
  1071. return task;
  1072. }
  1073. public override ValueTask<int> ReadBlockAsync(Memory<char> buffer, CancellationToken cancellationToken = default)
  1074. {
  1075. if (GetType() != typeof(StreamReader))
  1076. {
  1077. // If a derived type may have overridden ReadBlockAsync(char[], ...) before this overload
  1078. // was introduced, defer to it.
  1079. return base.ReadBlockAsync(buffer, cancellationToken);
  1080. }
  1081. if (_stream == null)
  1082. {
  1083. throw new ObjectDisposedException(null, SR.ObjectDisposed_ReaderClosed);
  1084. }
  1085. CheckAsyncTaskInProgress();
  1086. if (cancellationToken.IsCancellationRequested)
  1087. {
  1088. return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
  1089. }
  1090. ValueTask<int> vt = ReadBlockAsyncInternal(buffer, cancellationToken);
  1091. if (vt.IsCompletedSuccessfully)
  1092. {
  1093. return vt;
  1094. }
  1095. Task<int> t = vt.AsTask();
  1096. _asyncReadTask = t;
  1097. return new ValueTask<int>(t);
  1098. }
  1099. private async Task<int> ReadBufferAsync()
  1100. {
  1101. _charLen = 0;
  1102. _charPos = 0;
  1103. byte[] tmpByteBuffer = _byteBuffer;
  1104. Stream tmpStream = _stream;
  1105. if (!_checkPreamble)
  1106. {
  1107. _byteLen = 0;
  1108. }
  1109. do
  1110. {
  1111. if (_checkPreamble)
  1112. {
  1113. Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
  1114. int tmpBytePos = _bytePos;
  1115. int len = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos)).ConfigureAwait(false);
  1116. Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
  1117. if (len == 0)
  1118. {
  1119. // EOF but we might have buffered bytes from previous
  1120. // attempt to detect preamble that needs to be decoded now
  1121. if (_byteLen > 0)
  1122. {
  1123. _charLen += _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, _charLen);
  1124. // Need to zero out the _byteLen after we consume these bytes so that we don't keep infinitely hitting this code path
  1125. _bytePos = 0; _byteLen = 0;
  1126. }
  1127. return _charLen;
  1128. }
  1129. _byteLen += len;
  1130. }
  1131. else
  1132. {
  1133. Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
  1134. _byteLen = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer)).ConfigureAwait(false);
  1135. Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! Bug in stream class.");
  1136. if (_byteLen == 0) // We're at EOF
  1137. {
  1138. return _charLen;
  1139. }
  1140. }
  1141. // _isBlocked == whether we read fewer bytes than we asked for.
  1142. // Note we must check it here because CompressBuffer or
  1143. // DetectEncoding will change _byteLen.
  1144. _isBlocked = (_byteLen < tmpByteBuffer.Length);
  1145. // Check for preamble before detect encoding. This is not to override the
  1146. // user supplied Encoding for the one we implicitly detect. The user could
  1147. // customize the encoding which we will loose, such as ThrowOnError on UTF8
  1148. if (IsPreamble())
  1149. {
  1150. continue;
  1151. }
  1152. // If we're supposed to detect the encoding and haven't done so yet,
  1153. // do it. Note this may need to be called more than once.
  1154. if (_detectEncoding && _byteLen >= 2)
  1155. {
  1156. DetectEncoding();
  1157. }
  1158. _charLen += _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, _charLen);
  1159. } while (_charLen == 0);
  1160. return _charLen;
  1161. }
  1162. #endregion
  1163. // No data, class doesn't need to be serializable.
  1164. // Note this class is threadsafe.
  1165. private class NullStreamReader : StreamReader
  1166. {
  1167. // Instantiating Encoding causes unnecessary perf hit.
  1168. internal NullStreamReader()
  1169. {
  1170. Init(Stream.Null);
  1171. }
  1172. public override Stream BaseStream
  1173. {
  1174. get { return Stream.Null; }
  1175. }
  1176. public override Encoding CurrentEncoding
  1177. {
  1178. get { return Encoding.Unicode; }
  1179. }
  1180. protected override void Dispose(bool disposing)
  1181. {
  1182. // Do nothing - this is essentially unclosable.
  1183. }
  1184. public override int Peek()
  1185. {
  1186. return -1;
  1187. }
  1188. public override int Read()
  1189. {
  1190. return -1;
  1191. }
  1192. [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems.
  1193. public override int Read(char[] buffer, int index, int count)
  1194. {
  1195. return 0;
  1196. }
  1197. public override string ReadLine()
  1198. {
  1199. return null;
  1200. }
  1201. public override string ReadToEnd()
  1202. {
  1203. return string.Empty;
  1204. }
  1205. internal override int ReadBuffer()
  1206. {
  1207. return 0;
  1208. }
  1209. }
  1210. }
  1211. }