public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue) { ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input); SequencePosition scan1 = originalBuffer.Start; ReadOnlyBuffer <byte> buffer = originalBuffer; // Act SequencePosition?end = originalBuffer.PositionOf((byte)limitAfter); if (end.HasValue) { buffer = originalBuffer.Slice(buffer.Start, buffer.GetPosition(end.Value, 1)); } SequencePosition?returnValue1 = buffer.PositionOf((byte)seek); // Assert Assert.Equal(input.Contains(limitAfter), end.HasValue); if (expectedReturnValue != -1) { int expectedEndIndex = input.IndexOf(seek); Assert.NotNull(returnValue1); Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)), originalBuffer.Slice(returnValue1.Value).ToArray()); } }
public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue) { // Arrange ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input); // Act ReadOnlyBuffer <byte> buffer = limit > input.Length ? originalBuffer : originalBuffer.Slice(0, limit); SequencePosition?result = buffer.PositionOf((byte)seek); // Assert if (expectedReturnValue == -1) { Assert.Null(result); } else { Assert.NotNull(result); } if (expectedReturnValue != -1) { Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedBytesScanned - 1)), originalBuffer.Slice(result.Value).ToArray()); } }
public void MemorySeek(string raw, char searchFor, int expectIndex) { ReadOnlyBuffer <byte> cursors = Factory.CreateWithContent(raw); SequencePosition? result = cursors.PositionOf((byte)searchFor); Assert.NotNull(result); Assert.Equal(cursors.Slice(result.Value).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex))); }
private void ParseExtension(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { // Chunk-extensions not currently parsed // Just drain the data consumed = buffer.Start; examined = buffer.Start; do { SequencePosition?extensionCursorPosition = buffer.PositionOf(ByteCR); if (extensionCursorPosition == null) { // End marker not found yet consumed = buffer.End; examined = buffer.End; AddAndCheckConsumedBytes(buffer.Length); return; } ; var extensionCursor = extensionCursorPosition.Value; var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length; var sufixBuffer = buffer.Slice(extensionCursor); if (sufixBuffer.Length < 2) { consumed = extensionCursor; examined = buffer.End; AddAndCheckConsumedBytes(charsToByteCRExclusive); return; } sufixBuffer = sufixBuffer.Slice(0, 2); var sufixSpan = sufixBuffer.ToSpan(); if (sufixSpan[1] == '\n') { // We consumed the \r\n at the end of the extension, so switch modes. _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer; consumed = sufixBuffer.End; examined = sufixBuffer.End; AddAndCheckConsumedBytes(charsToByteCRExclusive + 2); } else { // Don't consume suffixSpan[1] in case it is also a \r. buffer = buffer.Slice(charsToByteCRExclusive + 1); consumed = extensionCursor; AddAndCheckConsumedBytes(charsToByteCRExclusive + 1); } } while (_mode == Mode.Extension); }
public void SequencePositionOfMultiSegment() { var(first, last) = BufferList.Create( new byte[] { 1, 2 }, new byte[] { 3, 4 } ); var bytes = new ReadOnlyBuffer <byte>(first, 0, last, last.Memory.Length); Assert.Equal(4, bytes.Length); // Static method call to avoid calling instance methods Assert.False(Sequence.PositionOf(bytes, 0).HasValue); for (int i = 0; i < bytes.Length; i++) { var value = (byte)(i + 1); var listPosition = MemoryListExtensions.PositionOf(first, value).GetValueOrDefault(); var(node, index) = listPosition.Get <IMemoryList <byte> >(); if (listPosition != default) { Assert.Equal(value, node.Memory.Span[index]); } var robPosition = bytes.PositionOf(value); var robSequencePosition = Sequence.PositionOf(bytes, value); Assert.Equal(listPosition, robPosition); Assert.Equal(listPosition, robSequencePosition); var robSlice = bytes.Slice(1); robPosition = robSlice.PositionOf(value); robSequencePosition = Sequence.PositionOf(robSlice, value); if (i > 0) { Assert.Equal(listPosition, robPosition); Assert.Equal(listPosition, robSequencePosition); } else { Assert.False(robPosition.HasValue); Assert.False(robSequencePosition.HasValue); } if (listPosition != default) { robSlice = bytes.Slice(listPosition); Assert.Equal(value, robSlice.First.Span[0]); } } }
private static void FindAllNewLines(ReadOnlyBuffer buffer) { while (true) { var position = buffer.PositionOf((byte)'\n'); if (position == null) { break; } buffer = buffer.Slice(position.Value).Slice(1); } }
public static bool TryParseMessage(ReadOnlyBuffer <byte> buffer, out NegotiationMessage negotiationMessage, out SequencePosition consumed, out SequencePosition examined) { var separator = buffer.PositionOf(TextMessageFormatter.RecordSeparator); if (separator == null) { // Haven't seen the entire negotiate message so bail consumed = buffer.Start; examined = buffer.End; negotiationMessage = null; return(false); } else { consumed = buffer.GetPosition(separator.Value, 1); examined = consumed; } var memory = buffer.IsSingleSegment ? buffer.First : buffer.ToArray(); return(TryParseMessage(memory.Span, out negotiationMessage)); }
public ParseResult ParseMessage(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined, out byte[] message) { consumed = buffer.Start; examined = buffer.End; message = null; var start = consumed; var end = examined; while (buffer.Length > 0) { if (!(buffer.PositionOf(ByteLF) is SequencePosition lineEnd)) { // For the case of data: Foo\r\n\r\<Anytine except \n> if (_internalParserState == InternalParseState.ReadEndOfMessage) { if (ConvertBufferToSpan(buffer.Slice(start, buffer.End)).Length > 1) { throw new FormatException("Expected a \\r\\n frame ending"); } } // Partial message. We need to read more. return(ParseResult.Incomplete); } lineEnd = buffer.GetPosition(lineEnd, 1); var line = ConvertBufferToSpan(buffer.Slice(start, lineEnd)); buffer = buffer.Slice(line.Length); if (line.Length <= 1) { throw new FormatException("There was an error in the frame format"); } // Skip comments if (line[0] == ByteColon) { start = lineEnd; consumed = lineEnd; continue; } if (IsMessageEnd(line)) { _internalParserState = InternalParseState.ReadEndOfMessage; } // To ensure that the \n was preceded by a \r // since messages can't contain \n. // data: foo\n\bar should be encoded as // data: foo\r\n // data: bar\r\n else if (line[line.Length - _sseLineEnding.Length] != ByteCR) { throw new FormatException("Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'"); } else { EnsureStartsWithDataPrefix(line); } var payload = Array.Empty <byte>(); switch (_internalParserState) { case InternalParseState.ReadMessagePayload: EnsureStartsWithDataPrefix(line); // Slice away the 'data: ' var payloadLength = line.Length - (_dataPrefix.Length + _sseLineEnding.Length); var newData = line.Slice(_dataPrefix.Length, payloadLength).ToArray(); _data.Add(newData); start = lineEnd; consumed = lineEnd; break; case InternalParseState.ReadEndOfMessage: if (_data.Count == 1) { payload = _data[0]; } else if (_data.Count > 1) { // Find the final size of the payload var payloadSize = 0; foreach (var dataLine in _data) { payloadSize += dataLine.Length; } payloadSize += _newLine.Length * _data.Count; // Allocate space in the payload buffer for the data and the new lines. // Subtract newLine length because we don't want a trailing newline. payload = new byte[payloadSize - _newLine.Length]; var offset = 0; foreach (var dataLine in _data) { dataLine.CopyTo(payload, offset); offset += dataLine.Length; if (offset < payload.Length) { _newLine.CopyTo(payload, offset); offset += _newLine.Length; } } } message = payload; consumed = lineEnd; examined = consumed; return(ParseResult.Completed); } if (buffer.Length > 0 && buffer.First.Span[0] == ByteCR) { _internalParserState = InternalParseState.ReadEndOfMessage; } } return(ParseResult.Incomplete); }