/// <summary> /// Try to read everything up to the given <paramref name="delimiter"/>. /// </summary> /// <param name="span">The read data, if any.</param> /// <param name="delimiter">The delimiter to look for.</param> /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param> /// <returns>True if the <paramref name="delimiter"/> was found.</returns> public bool TryReadTo(out ReadOnlySpan <T> span, T delimiter, bool advancePastDelimiter = true) { ReadOnlySpan <T> remaining = UnreadSpan; int index = MemoryExtensions.IndexOf(remaining, delimiter); if (index != -1) { span = index == 0 ? default : remaining.Slice(0, index); Advance(index + (advancePastDelimiter ? 1 : 0)); return(true); } return(TryReadToSlow(out span, delimiter, remaining.Length, advancePastDelimiter)); }
// TODO: this cannot be an extension method (as I would like it to be). // If I make it an extensions method, the compiler complains Span<T> cannot // be used as a type parameter. public static long IndexOf <TSequence>(TSequence sequence, byte value) where TSequence : ISequence <ReadOnlyMemory <byte> > { Position position = default; int totalIndex = 0; while (sequence.TryGet(ref position, out ReadOnlyMemory <byte> memory)) { var index = MemoryExtensions.IndexOf(memory.Span, value); if (index != -1) { return(index + totalIndex); } totalIndex += memory.Length; } return(-1); }
public static SequencePosition?PositionOf(this ReadOnlySequence <byte> sequence, byte value) { SequencePosition position = sequence.Start; SequencePosition result = position; while (sequence.TryGet(ref position, out ReadOnlyMemory <byte> memory)) { var index = MemoryExtensions.IndexOf(memory.Span, value); if (index != -1) { result = sequence.GetPosition(index, result); return(result); } result = position; } return(null); }
/// <summary> /// Finds the NAME in a message starting from an offset. /// Precisely extracts the NAME. /// Translates the NAME to a string. /// Moves forward the offset and returns the string. /// </summary> private static string HandleNAMEinMessage(ReadOnlySpan <byte> response, ref int offset, QueryTransport queryTransport) { int oldOffset = offset; ReadOnlySpan <byte> bytesNAME; if (response[offset] >= 0xc0) // domain name is compressed { bytesNAME = response.Slice(offset, 2); offset += 2; } else { // offset is relative to response offset = offset + MemoryExtensions.IndexOf(response.Slice(offset), (byte)0x00); bytesNAME = response.Slice(oldOffset, offset - oldOffset + 1); offset++; } return(NAMEToHostname(bytesNAME, response, queryTransport)); }
public static Collections.Sequences.Position?PositionOf <TSequence>(this TSequence sequence, byte value) where TSequence : ISequence <ReadOnlyMemory <byte> > { if (sequence == null) { return(null); } Collections.Sequences.Position position = sequence.First; Collections.Sequences.Position result = position; while (sequence.TryGet(ref position, out ReadOnlyMemory <byte> memory)) { var index = MemoryExtensions.IndexOf(memory.Span, value); if (index != -1) { result += index; return(result); } result = position; } return(null); }
public static SequencePosition?PositionOf <TSequence>(this TSequence sequence, byte value) where TSequence : ISequence <ReadOnlyMemory <byte> > { if (sequence == null) { return(null); } SequencePosition position = sequence.Start; SequencePosition result = position; while (sequence.TryGet(ref position, out ReadOnlyMemory <byte> memory)) { var index = MemoryExtensions.IndexOf(memory.Span, value); if (index != -1) { result = sequence.GetPosition(result, index); return(result); } result = position; } return(null); }
internal static bool TryParse(string?value, out GeoCoordinate?coordinate) { coordinate = null; if (value is null) { return(false); } int startIndex = 0; while (startIndex < value.Length) { char c = value[startIndex]; if (char.IsDigit(c) || c == '.') // ".8" == "0.8" { break; } startIndex++; } #if NET40 if (startIndex != 0) { value = value.Substring(startIndex); } value = value.Replace(';', ','); // vCard 3.0 string[] arr = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // vCard 4.0 try { NumberStyles numStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite; CultureInfo culture = CultureInfo.InvariantCulture; coordinate = new GeoCoordinate( double.Parse(arr[0].Trim(), numStyle, culture), double.Parse(arr[1].Trim(), numStyle, culture)); return(true); } catch { return(false); } #else ReadOnlySpan <char> roSpan = value.AsSpan(); if (startIndex != 0) { roSpan = roSpan.Slice(startIndex); } int splitIndex = MemoryExtensions.IndexOf(roSpan, ','); // vCard 4.0 if (splitIndex == -1) { splitIndex = MemoryExtensions.IndexOf(roSpan, ';'); // vCard 3.0 } try { NumberStyles numStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite; CultureInfo culture = CultureInfo.InvariantCulture; #if NET461 || NETSTANDARD2_0 coordinate = new GeoCoordinate( double.Parse(roSpan.Slice(0, splitIndex).ToString(), numStyle, culture), double.Parse(roSpan.Slice(splitIndex + 1).ToString(), numStyle, culture)); #else coordinate = new GeoCoordinate( double.Parse(roSpan.Slice(0, splitIndex), numStyle, culture), double.Parse(roSpan.Slice(splitIndex + 1), numStyle, culture)); #endif return(true); } catch { return(false); } #endif }
/// <summary> /// Parses the response message. /// </summary> private static void ParseResponse(ReadOnlySpan <byte> response, int queryLength, QTYPE qTYPE, QueryTransport queryTransport) { int offset = 0, tcpMsgLength = 0, questionOffset = 0; // Tcp & DoT pre-processing if (queryTransport == QueryTransport.Tcp || queryTransport == QueryTransport.DoT) { // save TcpMsgLength and remove it byte[] bytesTcpMsgLength = new byte[4]; Array.Copy(response.Slice(start: 0, length: 2).ToArray(), 0, bytesTcpMsgLength, 2, 2); tcpMsgLength = BinaryPrimitives.ReadInt32BigEndian(bytesTcpMsgLength); offset = 2; } // read header var bytesID = response.Slice(start: offset, length: 2); var bytesHeaderStuff = response.Slice(start: offset + 2, length: 2); var bytesQDCOUNT = response.Slice(start: offset + 4, length: 2); var bytesANCOUNT = response.Slice(start: offset + 6, length: 2); var bytesNSCOUNT = response.Slice(start: offset + 8, length: 2); var bytesARCOUNT = response.Slice(start: offset + 10, length: 2); // parse header int QR = (bytesHeaderStuff[0] & 0b1000_0000) >> 7; int OPCODE = (bytesHeaderStuff[0] & 0b0111_1000) >> 3; int AA = (bytesHeaderStuff[0] & 0b0000_0100) >> 2; int TC = (bytesHeaderStuff[0] & 0b0000_0010) >> 1; int RD = bytesHeaderStuff[0] & 0b0000_0001; int RA = (bytesHeaderStuff[1] & 0b1000_0000) >> 7; int Z = (bytesHeaderStuff[1] & 0b0111_0000) >> 4; int RCODE = bytesHeaderStuff[1] & 0b0000_1111; UInt16 QDCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesQDCOUNT); UInt16 ANCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesANCOUNT); UInt16 NSCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesNSCOUNT); UInt16 ARCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesARCOUNT); // checks /*if (bytesID[0] != 0x20 || bytesID[1] != 0x40 || QR != 1 || OPCODE != 0 || TC != 0 || RCODE != 0 || QDCOUNT != 1) || { || Console.WriteLine($"Warning: header checks failed."); || }*/ // read question // length of QNAME is unknown // look for 0x00 questionOffset = offset + 12; // offset is relative to response offset = questionOffset + MemoryExtensions.IndexOf(response.Slice(questionOffset), (byte)0x00); if (offset == -1) { Console.WriteLine("Error parsing response: invalid QNAME."); return; } var bytesQNAME = response.Slice(start: questionOffset, length: offset - questionOffset + 1); var bytesQTYPE = response.Slice(start: offset + 1, length: 2); var bytesQCLASS = response.Slice(start: offset + 3, length: 2); // parse question string QNAME = NAMEToHostname(bytesQNAME, response, queryTransport); UInt16 QTYPE = BinaryPrimitives.ReadUInt16BigEndian(bytesQTYPE); UInt16 QCLASS = BinaryPrimitives.ReadUInt16BigEndian(bytesQCLASS); // print info Console.WriteLine($@"Received bytes: {response.Length} ####### HEADER ####### ID: {BinaryPrimitives.ReadUInt16BigEndian(bytesID)} QR: {QR} OPCODE: {OPCODE} AA: {AA} TC: {TC} RD: {RD} RA: {RA} Z: {Z} RCODE: {RCODE} QDCOUNT: {QDCOUNT} ANCOUNT: {ANCOUNT} NSCOUNT: {NSCOUNT} ARCOUNT: {ARCOUNT} ####### QUESTION ####### QNAME: {QNAME} QTYPE: {QTYPE} QCLASS: {QCLASS}"); offset += 5; // Parse all RRs for (int i = 0; i < ANCOUNT; i++) { Console.WriteLine($"\n####### ANSWER #{i} #######"); ParseRR(response, ref offset, queryTransport); } for (int i = 0; i < NSCOUNT; i++) { Console.WriteLine($"\n####### AUTHORITY #{i} #######"); ParseRR(response, ref offset, queryTransport); } for (int i = 0; i < ARCOUNT; i++) { Console.WriteLine($"\n####### ADDITIONAL #{i} #######"); ParseRR(response, ref offset, queryTransport); } }