Пример #1
0
        /// <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));
        }
Пример #2
0
        // 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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        /// <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));
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
    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
    }
Пример #8
0
        /// <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);
            }
        }