public static void InvalidAdvance() { { var output = new ArrayBufferWriter <string>(); Assert.Throws <ArgumentException>(() => output.Advance(-1)); Assert.Throws <InvalidOperationException>(() => output.Advance(output.Capacity + 1)); } { var output = new ArrayBufferWriter <string>(); WriteData(output, 100); Assert.Throws <InvalidOperationException>(() => output.Advance(output.FreeCapacity + 1)); } }
public ReadOnlyMemory <byte> Sign(ReadOnlySpan <ValueTuple <AccountId, KeyPair> > signers, out Hash256 hash) { var signerArray = new Signer[signers.Length]; for (int i = 0; i < signers.Length; ++i) { var signer = new Signer(); signer.Account = signers[i].Item1; signer.SigningPubKey = signers[i].Item2.PublicKey.GetCanoncialBytes(); signer.TxnSignature = null; signerArray[i] = signer; } Signers = Array.AsReadOnly(signerArray); TxnSignature = null; SigningPubKey = null; var bufferWriter = new ArrayBufferWriter <byte>(); // Calculate signatures and then serialize again for (int i = 0; i < signers.Length; ++i) { // For each signer we need to write the account being signed for the the buffer, sign that then rewind System.Buffers.Binary.BinaryPrimitives.WriteUInt32BigEndian(bufferWriter.GetSpan(4), hpSMT); bufferWriter.Advance(4); Serialize(bufferWriter, true); Signers[i].Account.CopyTo(bufferWriter.GetSpan(20)); bufferWriter.Advance(20); signerArray[i].TxnSignature = signers[i].Item2.Sign(bufferWriter.WrittenSpan); bufferWriter.Clear(); } Array.Sort <Signer>(signerArray, (x, y) => x.Account.CompareTo(y.Account)); Signers = Array.AsReadOnly(signerArray); System.Buffers.Binary.BinaryPrimitives.WriteUInt32BigEndian(bufferWriter.GetSpan(4), hpTXN); bufferWriter.Advance(4); Serialize(bufferWriter, false); using (var sha512 = System.Security.Cryptography.SHA512.Create()) { Span <byte> hashSpan = stackalloc byte[64]; sha512.TryComputeHash(bufferWriter.WrittenSpan, hashSpan, out var bytesWritten); hash = new Hash256(hashSpan.Slice(0, 32)); } return(bufferWriter.WrittenMemory.Slice(4)); }
private async ValueTask <byte[]> ReadAsync( int length, CancellationToken cancellationToken = default) { if (length <= 0) { return(Array.Empty <byte>()); } var bufferWriter = new ArrayBufferWriter <byte>(length); System.IO.Pipelines.ReadResult result; do { result = await _reader.ReadAsync(cancellationToken) .ConfigureAwait(false); var buffer = result.Buffer.Slice( 0, Math.Min(bufferWriter.FreeCapacity, result.Buffer.Length)); buffer.CopyTo(bufferWriter.GetSpan()); bufferWriter.Advance((int)buffer.Length); _reader.AdvanceTo(buffer.End); } while (result.HasMoreData() && bufferWriter.WrittenCount < length); if (bufferWriter.WrittenCount < length) { throw new InvalidOperationException( $"Expected {length} bytes, got {bufferWriter.WrittenCount}"); } return(bufferWriter.WrittenMemory.ToArray()); }
public static void Advance() { { var output = new ArrayBufferWriter <byte>(); int capacity = output.Capacity; Assert.Equal(capacity, output.FreeCapacity); output.Advance(output.FreeCapacity); Assert.Equal(capacity, output.WrittenCount); Assert.Equal(0, output.FreeCapacity); } { var output = new ArrayBufferWriter <byte>(); output.Advance(output.Capacity); Assert.Equal(output.Capacity, output.WrittenCount); Assert.Equal(0, output.FreeCapacity); int previousCapacity = output.Capacity; Span <byte> _ = output.GetSpan(); Assert.True(output.Capacity > previousCapacity); } { var output = new ArrayBufferWriter <byte>(); WriteData(output, 2); ReadOnlyMemory <byte> previousMemory = output.WrittenMemory; ReadOnlySpan <byte> previousSpan = output.WrittenSpan; Assert.True(previousSpan.SequenceEqual(previousMemory.Span)); output.Advance(10); Assert.False(previousMemory.Span.SequenceEqual(output.WrittenMemory.Span)); Assert.False(previousSpan.SequenceEqual(output.WrittenSpan)); Assert.True(output.WrittenSpan.SequenceEqual(output.WrittenMemory.Span)); } }
public void ModbusFrameWriter_WriteFrame_CorrectlyWritesAReadInputRegistersRequest() { // Given var request = new RequestAdu { Header = new Header(transactionID: 1, unitID: 4), Pdu = new RequestReadInputRegisters { Address = 0x0040, Quantity = 0x000A, }, }; var arraybuffer = new ArrayBufferWriter <byte>(); // When var writer = new ModbusFrameWriter(arraybuffer); var position = writer.WriteFrame(request); arraybuffer.Advance(position); // Then var data = arraybuffer.WrittenSpan.ToArray(); Assert.Equal( new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x04, 0x04, 0x00, 0x40, 0x00, 0x0A }, data ); }
/// <summary> /// Reads messages from web socket and writes them to channel. /// Complete() will be called on channel writer when a close message is received from socket. /// On exception or cancellation, channel writer will not be set to complete. /// </summary> /// <exception cref="WebSocketException"></exception> /// <exception cref="OperationCanceledException"></exception> internal static async Task ReceiveLoop(this ChannelWriter <Message> channelWriter, WebSocket socket, CancellationToken cancellationToken) { Requires.NotNull(channelWriter, nameof(channelWriter)); Requires.NotNull(socket, nameof(socket)); var bufferWriter = new ArrayBufferWriter <byte>(); while (await ReadMessageAsync().ConfigureAwait(false)) { } async Task <bool> ReadMessageAsync() { ValueWebSocketReceiveResult result; do { result = await socket.ReceiveAsync(bufferWriter.GetMemory(), cancellationToken).ConfigureAwait(false); switch (result.MessageType) { case WebSocketMessageType.Text: case WebSocketMessageType.Binary: bufferWriter.Advance(result.Count); break; case WebSocketMessageType.Close: return(false); } } while (!result.EndOfMessage); channelWriter.TryWrite(new Message(Convert(result.MessageType), bufferWriter.WrittenSpan.ToArray())); bufferWriter.Clear(); return(true);
public void ModbusFrameWriter_WriteFrame_CorrectlyWritesAWriteSingleCoilRequest() { // Given var request = new RequestAdu { Header = new Header(transactionID: 1, unitID: 4), Pdu = new RequestWriteSingleCoil { Address = 0x0041, CoilState = true, }, }; var arraybuffer = new ArrayBufferWriter <byte>(); // When var writer = new ModbusFrameWriter(arraybuffer); var position = writer.WriteFrame(request); arraybuffer.Advance(position); // Then var data = arraybuffer.WrittenSpan.ToArray(); Assert.Equal( new byte[] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x04, 0x05, 0x00, 0x41, 0xFF, 0x00 }, data ); }
public void Advance() { { var output = new ArrayBufferWriter <T>(); int capacity = output.Capacity; Assert.Equal(capacity, output.FreeCapacity); output.Advance(output.FreeCapacity); Assert.Equal(capacity, output.WrittenCount); Assert.Equal(0, output.FreeCapacity); } { var output = new ArrayBufferWriter <T>(); output.Advance(output.Capacity); Assert.Equal(output.Capacity, output.WrittenCount); Assert.Equal(0, output.FreeCapacity); int previousCapacity = output.Capacity; Span <T> _ = output.GetSpan(); Assert.True(output.Capacity > previousCapacity); } { var output = new ArrayBufferWriter <T>(256); WriteData(output, 2); ReadOnlyMemory <T> previousMemory = output.WrittenMemory; ReadOnlySpan <T> previousSpan = output.WrittenSpan; Assert.True(previousSpan.SequenceEqual(previousMemory.Span)); output.Advance(10); Assert.False(previousMemory.Span.SequenceEqual(output.WrittenMemory.Span)); Assert.False(previousSpan.SequenceEqual(output.WrittenSpan)); Assert.True(output.WrittenSpan.SequenceEqual(output.WrittenMemory.Span)); } { var output = new ArrayBufferWriter <T>(); _ = output.GetSpan(20); WriteData(output, 10); ReadOnlyMemory <T> previousMemory = output.WrittenMemory; ReadOnlySpan <T> previousSpan = output.WrittenSpan; Assert.True(previousSpan.SequenceEqual(previousMemory.Span)); Assert.Throws <InvalidOperationException>(() => output.Advance(247)); output.Advance(10); Assert.False(previousMemory.Span.SequenceEqual(output.WrittenMemory.Span)); Assert.False(previousSpan.SequenceEqual(output.WrittenSpan)); Assert.True(output.WrittenSpan.SequenceEqual(output.WrittenMemory.Span)); } }
public async Task RunAndBlockAsync(Uri url, CancellationToken cancel) { var error = "Error."; var bufferWriter = new ArrayBufferWriter <byte>(CHUNK_SIZE); try { using (_ws = new ClientWebSocket()) { await _ws.ConnectAsync(url, cancel).ConfigureAwait(false); // WebsocketConnected!.Invoke(this); while (true) { var result = await _ws.ReceiveAsync(bufferWriter.GetMemory(CHUNK_SIZE), cancel); bufferWriter.Advance(result.Count); if (result.MessageType == WebSocketMessageType.Close) { var closeMessage = CloseCodes.GetErrorCodeMessage((int?)_ws.CloseStatus ?? 0).Message; error = $"Websocket closed ({_ws.CloseStatus}): {_ws.CloseStatusDescription} {closeMessage}"; break; } if (result.EndOfMessage) { var pr = PayloadReceived; var data = bufferWriter.WrittenMemory.ToArray(); bufferWriter.Clear(); if (!(pr is null)) { await pr.Invoke(data); } } } } } catch (WebSocketException ex) { Log.Warning("Disconnected, check your internet connection..."); Log.Debug(ex, "Websocket Exception in websocket client"); } catch (OperationCanceledException) { // ignored } catch (Exception ex) { Log.Error(ex, "Error in websocket client. {Message}", ex.Message); } finally { bufferWriter.Clear(); _ws = null; await ClosedAsync(error).ConfigureAwait(false); } }
private void Grow(int requiredSize) { if (_memory.Length == 0) { FirstGrow(requiredSize); return; } int sizeHint = Math.Max(DefaultGrowthSize, requiredSize); Debug.Assert(BytesPending != 0); if (_stream != null) { Debug.Assert(_arrayBufferWriter != null); _arrayBufferWriter.Advance(BytesPending); Debug.Assert(BytesPending == _arrayBufferWriter.WrittenCount); _stream.Write(_arrayBufferWriter.WrittenSpan); _arrayBufferWriter.Clear(); _memory = _arrayBufferWriter.GetMemory(sizeHint); Debug.Assert(_memory.Length >= sizeHint); } else { Debug.Assert(_output != null); _output.Advance(BytesPending); _memory = _output.GetMemory(sizeHint); if (_memory.Length < sizeHint) { // ToDo - replace this throw new Exception("Need more Span size"); } } BytesCommitted += BytesPending; BytesPending = 0; }
public void GetMemory_ExceedMaximumBufferSize() { var output = new ArrayBufferWriter <byte>(int.MaxValue / 2 + 1); output.Advance(int.MaxValue / 2 + 1); Memory <byte> memory = output.GetMemory(1); // Validate we can't double the buffer size, but can grow by sizeHint Assert.Equal(1, memory.Length); Assert.Throws <OutOfMemoryException>(() => output.GetMemory(int.MaxValue)); }
private void Append(ReadOnlyMemory <byte> segment) { _writer ??= new ArrayBufferWriter <byte>(); _segments ??= new List <ReadOnlyMemory <byte> >(); var memory = _writer.GetMemory(segment.Length); segment.CopyTo(memory); _writer.Advance(segment.Length); _segments.Add(memory.Slice(0, segment.Length)); }
/// <summary> /// Commits the JSON text written so far which makes it visible to the output destination. /// </summary> /// <remarks> /// In the case of IBufferWriter, this advances the underlying <see cref="IBufferWriter{Byte}" /> based on what has been written so far. /// In the case of Stream, this writes the data to the stream and flushes it. /// </remarks> /// <exception cref="ObjectDisposedException"> /// The instance of <see cref="Utf8JsonWriter"/> has been disposed. /// </exception> public void Flush() { CheckNotDisposed(); _memory = default; if (_stream != null) { Debug.Assert(_arrayBufferWriter != null); if (BytesPending != 0) { _arrayBufferWriter.Advance(BytesPending); BytesPending = 0; #if BUILDING_INBOX_LIBRARY _stream.Write(_arrayBufferWriter.WrittenSpan); #else Debug.Assert(_arrayBufferWriter.WrittenMemory.Length == _arrayBufferWriter.WrittenCount); bool result = MemoryMarshal.TryGetArray(_arrayBufferWriter.WrittenMemory, out ArraySegment <byte> underlyingBuffer); Debug.Assert(result); Debug.Assert(underlyingBuffer.Offset == 0); Debug.Assert(_arrayBufferWriter.WrittenCount == underlyingBuffer.Count); _stream.Write(underlyingBuffer.Array, underlyingBuffer.Offset, underlyingBuffer.Count); #endif BytesCommitted += _arrayBufferWriter.WrittenCount; _arrayBufferWriter.Clear(); } _stream.Flush(); } else { Debug.Assert(_output != null); if (BytesPending != 0) { _output.Advance(BytesPending); BytesCommitted += BytesPending; BytesPending = 0; } } }
public void ModbusFrameWriter_WriteFrame_CorrectlyWritesAWriteMultipleCoilsRequest(object request, byte[] expected) { // Given var arraybuffer = new ArrayBufferWriter <byte>(); // When var writer = new ModbusFrameWriter(arraybuffer); var position = writer.WriteFrame((RequestAdu)request); arraybuffer.Advance(position); // Then var data = arraybuffer.WrittenSpan.ToArray(); Assert.Equal(expected, data); }
/// <summary> /// Reads the data body of an AMQP message, transforming it for use /// as the body of an <see cref="EventData" /> instance. /// </summary> /// /// <param name="body">The body data set of an AMQP message.</param> /// /// <returns>A <see cref="BinaryData" /> representation of the <paramref name="body"/>.</returns> /// private static BinaryData ReadAmqpDataBody(IEnumerable <Data> body) { var writer = new ArrayBufferWriter <byte>(); foreach (var data in body) { var dataBytes = GetDataBytes(data); dataBytes.CopyTo(writer.GetMemory(dataBytes.Length)); writer.Advance(dataBytes.Length); } return((writer.WrittenCount > 0) ? BinaryData.FromBytes(writer.WrittenMemory) : new BinaryData(Array.Empty <byte>())); }
public void AdvanceZero() { var output = new ArrayBufferWriter <T>(); WriteData(output, 2); Assert.Equal(2, output.WrittenCount); ReadOnlyMemory <T> previousMemory = output.WrittenMemory; ReadOnlySpan <T> previousSpan = output.WrittenSpan; Assert.True(previousSpan.SequenceEqual(previousMemory.Span)); output.Advance(0); Assert.Equal(2, output.WrittenCount); Assert.True(previousMemory.Span.SequenceEqual(output.WrittenMemory.Span)); Assert.True(previousSpan.SequenceEqual(output.WrittenSpan)); Assert.True(output.WrittenSpan.SequenceEqual(output.WrittenMemory.Span)); }
// Returns via the out parameter the flattened collection of bytes. // A majority of the time, data will only contain 1 element. // The method is optimized for this situation to return the pre-existing array. public static BinaryData ConvertAndFlattenData(this IEnumerable <ReadOnlyMemory <byte> > dataList) { var writer = new ArrayBufferWriter <byte>(); Memory <byte> memory; foreach (ReadOnlyMemory <byte> data in dataList) { memory = writer.GetMemory(data.Length); data.CopyTo(memory); writer.Advance(data.Length); } if (writer.WrittenCount == 0) { return(new BinaryData(Array.Empty <byte>())); } return(BinaryData.FromBytes(writer.WrittenMemory)); }
// Returns via the out parameter the flattened collection of bytes. // A majority of the time, data will only contain 1 element. // The method is optimized for this situation to return the pre-existing array. public static BinaryData ConvertAndFlattenData(this IEnumerable <BinaryData> dataList) { var writer = new ArrayBufferWriter <byte>(); Memory <byte> memory; foreach (BinaryData data in dataList) { ReadOnlyMemory <byte> bytes = data.ToBytes(); memory = writer.GetMemory(bytes.Length); bytes.CopyTo(memory); writer.Advance(bytes.Length); } if (writer.WrittenCount == 0) { return(new BinaryData()); } return(BinaryData.FromBytes(writer.WrittenMemory)); }
public void GetMemory_ExceedMaximumBufferSize() { const int MaxArrayLength = 0X7FEFFFFF; int initialCapacity = int.MaxValue / 2 + 1; var output = new ArrayBufferWriter <byte>(initialCapacity); output.Advance(initialCapacity); // Validate we can't double the buffer size, but can grow Memory <byte> memory = output.GetMemory(1); // The buffer should grow more than the 1 byte requested otherwise performance will not be usable // between 1GB and 2GB. The current implementation maxes out the buffer size to MaxArrayLength. Assert.Equal(MaxArrayLength - initialCapacity, memory.Length); Assert.Throws <OutOfMemoryException>(() => output.GetMemory(int.MaxValue)); }
// StorageKey.Key uses an atypical storage pattern relative to other models in Neo. // The byte array is written in blocks of BLOCK_SIZE (aka 16) bytes followed by a byte // indicating how many bytes of the previous block were padding. Only the last block is // allowed to have padding. Read blocks of BLOCK_SIZE + 1 until padding indication byte // is greater than zero. public static bool TryRead(ref BufferReader <byte> reader, out StorageKey value) { const int READ_BLOCK_SIZE = BLOCK_SIZE + 1; if (UInt160.TryRead(ref reader, out var scriptHash)) { using var bufferOwner = MemoryPool <byte> .Shared.Rent(READ_BLOCK_SIZE); var buffer = bufferOwner.Memory.Slice(0, READ_BLOCK_SIZE).Span; var writer = new ArrayBufferWriter <byte>(); while (true) { if (!reader.TryCopyTo(buffer)) { value = default; return(false); } reader.Advance(READ_BLOCK_SIZE); var dataSize = BLOCK_SIZE - buffer[BLOCK_SIZE]; buffer.Slice(0, dataSize).CopyTo(writer.GetSpan(dataSize)); writer.Advance(dataSize); if (dataSize < BLOCK_SIZE) { break; } } // unfortunately, since we don't know a priori how many blocks there will be // or how much padding the last block will have, we have to make another copy // of the key array. However, we can use Unsafe.As to cast the mutable key array // into an ImmutableArray var keyArray = writer.WrittenSpan.ToArray(); value = new StorageKey(scriptHash, Unsafe.As <byte[], ImmutableArray <byte> >(ref keyArray)); return(true); } value = default; return(false); }
/// <summary> /// Appends a memory segment to the continuous buffer. /// </summary> /// /// <param name="segment">The memory segment to append.</param> /// private void AppendSegment(Data segment) { _writer ??= new ArrayBufferWriter <byte>(); _segments ??= new List <ReadOnlyMemory <byte> >(); ReadOnlyMemory <byte> dataToAppend = segment.Value switch { byte[] byteArray => byteArray, ArraySegment <byte> arraySegment => arraySegment, _ => ReadOnlyMemory <byte> .Empty }; var memory = _writer.GetMemory(dataToAppend.Length); dataToAppend.CopyTo(memory); _writer.Advance(dataToAppend.Length); _segments.Add(memory.Slice(0, dataToAppend.Length)); } }
private void Append(Data segment) { // fields are lazy initialized to not occupy unnecessary memory when there are no data segments _writer ??= new ArrayBufferWriter <byte>(); _segments ??= new List <ReadOnlyMemory <byte> >(); ReadOnlyMemory <byte> dataToAppend = segment.Value switch { byte[] byteArray => byteArray, ArraySegment <byte> arraySegment => arraySegment, _ => ReadOnlyMemory <byte> .Empty }; var memory = _writer.GetMemory(dataToAppend.Length); dataToAppend.CopyTo(memory); _writer.Advance(dataToAppend.Length); _segments.Add(memory.Slice(0, dataToAppend.Length)); } }
public void GetMemory_ExceedMaximumBufferSize() { int initialCapacity = int.MaxValue / 2 + 1; try { var output = new ArrayBufferWriter <byte>(initialCapacity); output.Advance(initialCapacity); // Validate we can't double the buffer size, but can grow Memory <byte> memory; memory = output.GetMemory(1); // The buffer should grow more than the 1 byte requested otherwise performance will not be usable // between 1GB and 2GB. The current implementation maxes out the buffer size to Array.MaxLength. Assert.Equal(Array.MaxLength - initialCapacity, memory.Length); Assert.Throws <OutOfMemoryException>(() => output.GetMemory(int.MaxValue)); } catch (OutOfMemoryException) { // On memory constrained devices, we can get an OutOfMemoryException, which we can safely ignore. } }
public string[] ReadHeaderLines() { if (State != ReaderState.Headers) { throw new InvalidOperationException(); } List <string> lines = new List <string>(); var outputBuffer = new ArrayBufferWriter <byte>(); if (endOfClearText) { // If we were reading clear text before then we consumed // the first two dashes of the separator. outputBuffer.Write(new[] { (byte)'-', (byte)'-' }); } for (; ;) { var b = innerStream.ReadByte(); switch (b) { case -1: return(Array.Empty <string>()); case '\n': if (!ignoreNL) { goto case '\r'; } ignoreNL = false; break; case '\r': ignoreNL = b == '\r'; // Non-empty line string?line = null; if (outputBuffer.WrittenCount > 0) { line = Encoding.ASCII.GetString(outputBuffer.WrittenSpan); outputBuffer.Clear(); } if (!string.IsNullOrWhiteSpace(line)) { lines.Add(line); } else if (lines.Count > 0) { // TODO: Verify the headers headerEndLineLength = lines.First().Length - 2; // -2 for BEGIN -> END State = !endOfClearText && Equals(lines.FirstOrDefault(), "-----BEGIN PGP SIGNED MESSAGE-----") ? ReaderState.ClearText : ReaderState.Base64; return(lines.ToArray()); } break; default: outputBuffer.GetSpan(1)[0] = (byte)b; outputBuffer.Advance(1); break; } } }
public int ReadClearText(Span <byte> buffer) { if (State != ReaderState.ClearText) { throw new InvalidOperationException(); } // We usually try to output one character for one input character // but new line and dash sequences can produce up to 4 characters // at once, so size the buffer to accommodate that. We can also // overshoot the buffer with pending whitespace. var outputBuffer = new ArrayBufferWriter <byte>(buffer.Length + 3); if (pendingData != null) { outputBuffer.Write(pendingData); } while (!endOfClearText && outputBuffer.WrittenCount < buffer.Length) { var b = innerStream.ReadByte(); // End of stream if (b == -1) { break; } switch (b) { case ' ': case '\t': // Collect pending whitespace because it could be trailing whitespace // at end of line pendingWhitespace.GetSpan(1)[0] = (byte)b; pendingWhitespace.Advance(1); break; case '\r': case '\n': // Ignore \n that was still part of header if (ignoreNL && b == '\n') { ignoreNL = false; break; } // Discard any pending whitespace pendingWhitespace.Clear(); // Read next character after the new line var nextB = innerStream.ReadByte(); if (b == '\r' && nextB == '\n') { nextB = innerStream.ReadByte(); } if (nextB == '-') { // New line followed byt dash. Now we are looking either at the end of // clear text or a dash escape nextB = innerStream.ReadByte(); if (nextB == ' ') { // Dash escape, remove it and flush the new line outputBuffer.Write(new[] { (byte)'\r', (byte)'\n' }); } else if (nextB == '-') { // Possible end of clear text endOfClearText = true; break; } else { // Invalid clear text, flush the new lind and output it var clearText = outputBuffer.GetSpan(4); clearText[0] = (byte)'\r'; clearText[1] = (byte)'\n'; clearText[2] = (byte)'-'; clearText[3] = (byte)nextB; outputBuffer.Advance(4); } } else { // Flush the new line outputBuffer.Write(new[] { (byte)'\r', (byte)'\n' }); if (nextB == '\r' || nextB == '\n') { b = nextB; goto case '\r'; } else if (nextB == ' ' || nextB == '\t') { pendingWhitespace.GetSpan(1)[0] = (byte)nextB; pendingWhitespace.Advance(1); } else { outputBuffer.GetSpan(1)[0] = (byte)nextB; outputBuffer.Advance(1); } } break; default: // Flush any pending whitespace if (pendingWhitespace.WrittenCount > 0) { outputBuffer.Write(pendingWhitespace.WrittenSpan); pendingWhitespace.Clear(); } outputBuffer.GetSpan(1)[0] = (byte)b; outputBuffer.Advance(1); break; } } if (outputBuffer.WrittenCount > buffer.Length) { pendingData = outputBuffer.WrittenSpan.Slice(buffer.Length).ToArray(); outputBuffer.WrittenSpan.Slice(0, buffer.Length).CopyTo(buffer); return(buffer.Length); } else { if (endOfClearText) { State = ReaderState.Headers; } pendingData = null; outputBuffer.WrittenSpan.CopyTo(buffer); return(outputBuffer.WrittenCount); } }