AngleSharp by AngleSharp

<PackageReference Include="AngleSharp" Version="1.1.0-alpha-375" />

 WritableTextSource

using AngleSharp.Common; using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AngleSharp.Text { internal sealed class WritableTextSource : ITextSource, IReadOnlyTextSource, IDisposable { private enum EncodingConfidence : byte { Tentative, Certain, Irrelevant } private const int BufferSize = 4096; private readonly Stream _baseStream; private readonly MemoryStream _raw; private readonly byte[] _buffer; private readonly char[] _chars; private StringBuilder _content; private EncodingConfidence _confidence; private bool _finished; private Encoding _encoding; private Decoder _decoder; private int _index; [System.Diagnostics.CodeAnalysis.MemberNotNull("_content")] public string Text { [System.Diagnostics.CodeAnalysis.MemberNotNull("_content")] get { return _content.ToString(); } } public char this[int index] { get { return Replace(_content[index]); } } public int Length => _content.Length; public Encoding CurrentEncoding { get { return _encoding; } set { if (_confidence == EncodingConfidence.Tentative) { if (_encoding.IsUnicode()) _confidence = EncodingConfidence.Certain; else { if (value.IsUnicode()) value = TextEncoding.Utf8; if (value == _encoding) _confidence = EncodingConfidence.Certain; else { _encoding = value; _decoder = value.GetDecoder(); byte[] array = _raw.ToArray(); char[] array2 = new char[_encoding.GetMaxCharCount(array.Length)]; int chars = _decoder.GetChars(array, 0, array.Length, array2, 0); string text = new string(array2, 0, chars); int num = Math.Min(_index, text.Length); if (!text.Substring(0, num).Is(_content.ToString(0, num))) { _index = 0; _content.Clear().Append(text); throw new NotSupportedException(); } _confidence = EncodingConfidence.Certain; _content.Remove(num, _content.Length - num); _content.Append(text.Substring(num)); } } } } } public int Index { get { return _index; } set { _index = value; } } private WritableTextSource(Encoding encoding, bool allocateBuffers) { if (allocateBuffers) { _buffer = new byte[4096]; _chars = new char[4097]; } _raw = new MemoryStream(); _index = 0; _encoding = (encoding ?? TextEncoding.Utf8); _decoder = _encoding.GetDecoder(); } public WritableTextSource(string source) : this(null, TextEncoding.Utf8) { _finished = true; _content.Append(source); _confidence = EncodingConfidence.Irrelevant; } public WritableTextSource(Stream baseStream, Encoding encoding = null) : this(encoding, baseStream != null) { _baseStream = baseStream; _content = StringBuilderPool.Obtain(); _confidence = EncodingConfidence.Tentative; } public void Dispose() { if (_content != null) { _raw.Dispose(); _content.Clear().ReturnToPool(); _content = null; } } public char ReadCharacter() { if (_index < _content.Length) return Replace(_content[_index++]); ExpandBuffer(4096); int num = _index++; if (num >= _content.Length) return '￿'; return Replace(_content[num]); } public string ReadCharacters(int characters) { int index = _index; if (index + characters <= _content.Length) { _index += characters; return _content.ToString(index, characters); } ExpandBuffer(Math.Max(4096, characters)); _index += characters; characters = Math.Min(characters, _content.Length - index); return _content.ToString(index, characters); } public StringOrMemory ReadMemory(int characters) { return new StringOrMemory(ReadCharacters(characters)); } public Task PrefetchAsync(int length, CancellationToken cancellationToken) { return ExpandBufferAsync(length, cancellationToken); } [AsyncStateMachine(typeof(<PrefetchAllAsync>d__31))] public Task PrefetchAllAsync(CancellationToken cancellationToken) { <PrefetchAllAsync>d__31 stateMachine = default(<PrefetchAllAsync>d__31); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public bool TryGetContentLength(out int length) { length = 0; return false; } public void InsertText(string content) { if (_index >= 0 && _index < _content.Length) _content.Insert(_index, content); else _content.Append(content); _index += content.Length; } private static char Replace(char c) { if (c != '￿') return c; return '�'; } [AsyncStateMachine(typeof(<DetectByteOrderMarkAsync>d__35))] private Task DetectByteOrderMarkAsync(CancellationToken cancellationToken) { <DetectByteOrderMarkAsync>d__35 stateMachine = default(<DetectByteOrderMarkAsync>d__35); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } [AsyncStateMachine(typeof(<ExpandBufferAsync>d__36))] private Task ExpandBufferAsync(long size, CancellationToken cancellationToken) { <ExpandBufferAsync>d__36 stateMachine = default(<ExpandBufferAsync>d__36); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.size = size; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } [AsyncStateMachine(typeof(<ReadIntoBufferAsync>d__37))] private Task ReadIntoBufferAsync(CancellationToken cancellationToken) { <ReadIntoBufferAsync>d__37 stateMachine = default(<ReadIntoBufferAsync>d__37); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } private void ExpandBuffer(long size) { if (!_finished && _content.Length == 0) DetectByteOrderMarkAsync(CancellationToken.None).Wait(); while (!_finished && size + _index > _content.Length) { ReadIntoBuffer(); } } private void ReadIntoBuffer() { int size = _baseStream.Read(_buffer, 0, 4096); AppendContentFromBuffer(size); } private void AppendContentFromBuffer(int size) { _finished = (size == 0); int chars = _decoder.GetChars(_buffer, 0, size, _chars, 0); if (_confidence != EncodingConfidence.Certain) _raw.Write(_buffer, 0, size); _content.Append(_chars, 0, chars); } } }