< Summary

Line coverage
19%
Covered lines: 52
Uncovered lines: 215
Coverable lines: 267
Total lines: 707
Line coverage: 19.4%
Branch coverage
14%
Covered branches: 27
Total branches: 186
Branch coverage: 14.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: FindCompressionRange(...)0%880%
File 1: ShouldHaveIpv4Embedded(...)0%22220%
File 1: Parse(...)0%68680%
File 2: ParseCanonicalName(...)0%18180%
File 2: IsLoopback(...)0%22220%
File 2: IsValid(...)56.25%484867.53%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/Common/src/System/Net/IPv6AddressHelper.Common.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Numerics;
 6
 7namespace System.Net
 8{
 9    internal static partial class IPv6AddressHelper
 10    {
 11        private const int Hex = 16;
 12        private const int NumberOfLabels = 8;
 13
 14        // RFC 5952 Section 4.2.3
 15        // Longest consecutive sequence of zero segments, minimum 2.
 16        // On equal, first sequence wins. <-1, -1> for no compression.
 17        internal static (int longestSequenceStart, int longestSequenceLength) FindCompressionRange(ReadOnlySpan<ushort> 
 018        {
 019            int longestSequenceLength = 0, longestSequenceStart = -1, currentSequenceLength = 0;
 20
 021            for (int i = 0; i < numbers.Length; i++)
 022            {
 023                if (numbers[i] == 0)
 024                {
 025                    currentSequenceLength++;
 026                    if (currentSequenceLength > longestSequenceLength)
 027                    {
 028                        longestSequenceLength = currentSequenceLength;
 029                        longestSequenceStart = i - currentSequenceLength + 1;
 030                    }
 031                }
 32                else
 033                {
 034                    currentSequenceLength = 0;
 035                }
 036            }
 37
 038            return longestSequenceLength > 1 ?
 039                (longestSequenceStart, longestSequenceStart + longestSequenceLength) :
 040                (-1, 0);
 041        }
 42
 43        // Returns true if the IPv6 address should be formatted with an embedded IPv4 address:
 44        // ::192.168.1.1
 45        internal static bool ShouldHaveIpv4Embedded(ReadOnlySpan<ushort> numbers)
 046        {
 47            // 0:0 : 0:0 : x:x : x.x.x.x
 048            if (numbers[0] == 0 && numbers[1] == 0 && numbers[2] == 0 && numbers[3] == 0 && numbers[6] != 0)
 049            {
 50                // RFC 5952 Section 5 - 0:0 : 0:0 : 0:[0 | FFFF] : x.x.x.x
 051                if (numbers[4] == 0 && (numbers[5] == 0 || numbers[5] == 0xFFFF))
 052                {
 053                    return true;
 54                }
 55                // SIIT - 0:0 : 0:0 : FFFF:0 : x.x.x.x
 056                else if (numbers[4] == 0xFFFF && numbers[5] == 0)
 057                {
 058                    return true;
 59                }
 060            }
 61
 62            // ISATAP
 063            return numbers[4] == 0 && numbers[5] == 0x5EFE;
 064        }
 65
 66        //
 67        // IsValidStrict
 68        //
 69        //  Determine whether a name is a valid IPv6 address. Rules are:
 70        //
 71        //   *  8 groups of 16-bit hex numbers, separated by ':'
 72        //   *  a *single* run of zeros can be compressed using the symbol '::'
 73        //   *  an optional string of a ScopeID delimited by '%'
 74        //   *  the last 32 bits in an address can be represented as an IPv4 address
 75        //
 76        //  Difference between IsValid() and IsValidStrict() is that IsValid() expects part of the string to
 77        //  be ipv6 address where as IsValidStrict() expects strict ipv6 address.
 78        //
 79        // Inputs:
 80        //  <argument>  name
 81        //      IPv6 address in string format
 82        //
 83        // Outputs:
 84        //  Nothing
 85        //
 86        // Assumes:
 87        //  the correct name is terminated by  ']' character
 88        //
 89        // Returns:
 90        //  true if <name> is IPv6  address, else false
 91        //
 92        // Throws:
 93        //  Nothing
 94        //
 95
 96        //  Remarks: MUST NOT be used unless all input indexes are verified and trusted.
 97        //           start must be next to '[' position, or error is reported
 98        internal static bool IsValidStrict<TChar>(ReadOnlySpan<TChar> name)
 99            where TChar : unmanaged, IBinaryInteger<TChar>
 100        {
 101            Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
 102
 103            // Number of components in this IPv6 address
 104            int sequenceCount = 0;
 105            // Length of the component currently being constructed
 106            int sequenceLength = 0;
 107            bool haveCompressor = false;
 108            bool haveIPv4Address = false;
 109            bool expectingNumber = true;
 110            // Start position of the previous component
 111            int lastSequence = 1;
 112            int start = 0;
 113            int end = name.Length;
 114
 115            bool needsClosingBracket = false;
 116
 117            // An IPv6 address may begin with a start character ('['). If it does, it must end with an end
 118            // character (']').
 119            if (start < end && name[start] == TChar.CreateTruncating('['))
 120            {
 121                start++;
 122                needsClosingBracket = true;
 123
 124                // IsValidStrict() is only called if there is a ':' in the name string, i.e.
 125                // it is a possible IPv6 address. So, if the string starts with a '[' and
 126                // the pointer is advanced here there are still more characters to parse.
 127                Debug.Assert(start < end);
 128            }
 129
 130            // Starting with a colon character is only valid if another colon follows.
 131            if (name[start] == TChar.CreateTruncating(':') && (start + 1 >= end || name[start + 1] != TChar.CreateTrunca
 132            {
 133                return false;
 134            }
 135
 136            int i;
 137            for (i = start; i < end; ++i)
 138            {
 139                int currentCh = IPv4AddressHelper.ToUShort(name[i]);
 140
 141                if (HexConverter.IsHexChar(currentCh))
 142                {
 143                    ++sequenceLength;
 144                    expectingNumber = false;
 145                }
 146                else
 147                {
 148                    if (sequenceLength > 4)
 149                    {
 150                        return false;
 151                    }
 152                    if (sequenceLength != 0)
 153                    {
 154                        ++sequenceCount;
 155                        lastSequence = i - sequenceLength;
 156                        sequenceLength = 0;
 157                    }
 158
 159                    switch (currentCh)
 160                    {
 161                        case '%':
 162                            // An IPv6 address is separated from its scope by a '%' character. The scope
 163                            // is terminated by the natural end of the address, the address end character (']')
 164                            // or the start of the prefix ('/').
 165                            while (i + 1 < end)
 166                            {
 167                                i++;
 168                                if (name[i] == TChar.CreateTruncating(']'))
 169                                {
 170                                    goto case ']';
 171                                }
 172                                else if (name[i] == TChar.CreateTruncating('/'))
 173                                {
 174                                    goto case '/';
 175                                }
 176                            }
 177                            break;
 178
 179                        case ']':
 180                            if (!needsClosingBracket)
 181                            {
 182                                return false;
 183                            }
 184                            needsClosingBracket = false;
 185
 186                            // If there's more after the closing bracket, it must be a port.
 187                            // We don't use the port, but we still validate it.
 188                            if (i + 1 < end && name[i + 1] != TChar.CreateTruncating(':'))
 189                            {
 190                                return false;
 191                            }
 192
 193                            // If there is a port, it must either be a hexadecimal or decimal number.
 194                            // If the next two characters are '0x' then it's a hexadecimal number. Skip the prefix.
 195                            if (i + 3 < end && name[i + 2] == TChar.CreateTruncating('0') && name[i + 3] == TChar.Create
 196                            {
 197                                i += 4;
 198                                for (; i < end; i++)
 199                                {
 200                                    int ch = IPv4AddressHelper.ToUShort(name[i]);
 201
 202                                    if (!HexConverter.IsHexChar(ch))
 203                                    {
 204                                        return false;
 205                                    }
 206                                }
 207                            }
 208                            else
 209                            {
 210                                i += 2;
 211                                for (; i < end; i++)
 212                                {
 213                                    if (!char.IsAsciiDigit((char)IPv4AddressHelper.ToUShort(name[i])))
 214                                    {
 215                                        return false;
 216                                    }
 217                                }
 218                            }
 219                            continue;
 220
 221                        case ':':
 222                            // If the next character after a colon is another colon, the address contains a compressor (
 223                            if ((i > 0) && (name[i - 1] == TChar.CreateTruncating(':')))
 224                            {
 225                                if (haveCompressor)
 226                                {
 227                                    // can only have one per IPv6 address
 228                                    return false;
 229                                }
 230                                haveCompressor = true;
 231                                expectingNumber = false;
 232                            }
 233                            else
 234                            {
 235                                expectingNumber = true;
 236                            }
 237                            break;
 238
 239                        case '/':
 240                            // A prefix in an IPv6 address is invalid.
 241                            return false;
 242
 243                        case '.':
 244                            if (haveIPv4Address)
 245                            {
 246                                return false;
 247                            }
 248
 249                            if (!IPv4AddressHelper.IsValid(name.Slice(lastSequence, end - lastSequence), out int seqEnd,
 250                            {
 251                                return false;
 252                            }
 253                            i = lastSequence + seqEnd;
 254
 255                            // An IPv4 address takes 2 slots in an IPv6 address. One was just counted meeting the '.'
 256                            ++sequenceCount;
 257                            lastSequence = i - sequenceLength;
 258                            haveIPv4Address = true;
 259                            --i;            // it will be incremented back on the next loop
 260                            break;
 261
 262                        default:
 263                            return false;
 264                    }
 265                    sequenceLength = 0;
 266                }
 267            }
 268
 269            if (sequenceLength != 0)
 270            {
 271                if (sequenceLength > 4)
 272                {
 273                    return false;
 274                }
 275
 276                ++sequenceCount;
 277            }
 278
 279            // These sequence counts are -1 because it is implied in end-of-sequence.
 280
 281            const int ExpectedSequenceCount = 8;
 282            return
 283                !expectingNumber &&
 284                (haveCompressor ? (sequenceCount < ExpectedSequenceCount) : (sequenceCount == ExpectedSequenceCount)) &&
 285                !needsClosingBracket;
 286        }
 287
 288        //
 289        // Parse
 290        //
 291        //  Convert this IPv6 address into a sequence of 8 16-bit numbers
 292        //
 293        // Inputs:
 294        //  <member>    Name
 295        //      The validated IPv6 address
 296        //
 297        // Outputs:
 298        //  <member>    numbers
 299        //      Array filled in with the numbers in the IPv6 groups
 300        //
 301        //  <member>    scopeId
 302        //      Set to the text after the scope separator (%) if found
 303        //
 304        // Assumes:
 305        //  <Name> has been validated and contains only hex digits in groups of
 306        //  16-bit numbers, the characters ':', '/' and '%', and a possible IPv4
 307        //  address
 308        //
 309        // Throws:
 310        //  Nothing
 311        //
 312
 313        internal static void Parse<TChar>(ReadOnlySpan<TChar> address, scoped Span<ushort> numbers, out ReadOnlySpan<TCh
 314            where TChar : unmanaged, IBinaryInteger<TChar>
 0315        {
 0316            Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte));
 317
 0318            int number = 0;
 319            int currentCh;
 0320            int index = 0;
 0321            int compressorIndex = -1;
 0322            bool numberIsValid = true;
 323
 0324            scopeId = ReadOnlySpan<TChar>.Empty;
 325
 326            // Skip the start '[' character, if present. Stop parsing at the end IPv6 address terminator (']').
 0327            for (int i = (address[0] == TChar.CreateTruncating('[') ? 1 : 0); i < address.Length && address[i] != TChar.
 0328            {
 0329                currentCh = IPv4AddressHelper.ToUShort(address[i]);
 330
 0331                switch (currentCh)
 332                {
 333                    case '%':
 0334                        if (numberIsValid)
 0335                        {
 0336                            numbers[index++] = (ushort)number;
 0337                            numberIsValid = false;
 0338                        }
 339
 340                        // The scope follows a '%' and terminates at the natural end of the address, the address termina
 0341                        int scopeStart = i;
 342
 0343                        for (++i; i < address.Length && address[i] != TChar.CreateTruncating(']') && address[i] != TChar
 0344                        {
 0345                        }
 0346                        scopeId = address.Slice(scopeStart, i - scopeStart);
 347
 348                        // Ignore the prefix (if any.)
 0349                        for (; i < address.Length && address[i] != TChar.CreateTruncating(']'); ++i)
 0350                        {
 0351                        }
 0352                        break;
 353
 354                    case ':':
 0355                        numbers[index++] = (ushort)number;
 0356                        number = 0;
 357                        // Two sequential colons form a compressor ('::').
 0358                        ++i;
 0359                        if (address[i] == TChar.CreateTruncating(':'))
 0360                        {
 0361                            compressorIndex = index;
 0362                            ++i;
 0363                        }
 0364                        else if ((compressorIndex < 0) && (index < 6))
 0365                        {
 366                            // No point checking for IPv4 address if we don't
 367                            // have a compressor or we haven't seen 6 16-bit
 368                            // numbers yet.
 0369                            break;
 370                        }
 371
 372                        // Check to see if the upcoming number is really an IPv4
 373                        // address. If it is, convert it to 2 ushort numbers
 0374                        for (int j = i; j < address.Length &&
 0375                                        (address[j] != TChar.CreateTruncating(']')) &&
 0376                                        (address[j] != TChar.CreateTruncating(':')) &&
 0377                                        (address[j] != TChar.CreateTruncating('%')) &&
 0378                                        (address[j] != TChar.CreateTruncating('/')) &&
 0379                                        (j < i + 4); ++j)
 0380                        {
 381
 0382                            if (address[j] == TChar.CreateTruncating('.'))
 0383                            {
 384                                // We have an IPv4 address. Find the end of it:
 385                                // we know that since we have a valid IPv6
 386                                // address, the only things that will terminate
 387                                // the IPv4 address are the prefix delimiter '/'
 388                                // or the end-of-string (which we conveniently
 389                                // delimited with ']').
 0390                                while (j < address.Length && (address[j] != TChar.CreateTruncating(']')) && (address[j] 
 0391                                {
 0392                                    ++j;
 0393                                }
 0394                                int ipv4Address = IPv4AddressHelper.ParseHostNumber(address, i, j);
 395
 0396                                numbers[index++] = (ushort)(ipv4Address >> 16);
 0397                                numbers[index++] = (ushort)(ipv4Address & 0xFFFF);
 0398                                i = j;
 399
 400                                // Set this to avoid adding another number to
 401                                // the array if there's a prefix
 0402                                number = 0;
 0403                                numberIsValid = false;
 0404                                break;
 405                            }
 0406                        }
 0407                        break;
 408
 409                    case '/':
 0410                        if (numberIsValid)
 0411                        {
 0412                            numbers[index++] = (ushort)number;
 0413                            numberIsValid = false;
 0414                        }
 415
 0416                        for (++i; i < address.Length && address[i] != TChar.CreateTruncating(']'); i++)
 0417                        {
 0418                        }
 419
 0420                        break;
 421
 422                    default:
 0423                        int characterValue = HexConverter.FromChar(currentCh);
 424
 0425                        number = number * IPv6AddressHelper.Hex + characterValue;
 0426                        i++;
 0427                        break;
 428                }
 0429            }
 430
 431            // Add number to the array if it's not the prefix length or part of
 432            // an IPv4 address that's already been handled
 0433            if (numberIsValid)
 0434            {
 0435                numbers[index++] = (ushort)number;
 0436            }
 437
 438            // If we had a compressor sequence ("::") then we need to expand the
 439            // numbers array.
 0440            if (compressorIndex > 0)
 0441            {
 0442                int toIndex = NumberOfLabels - 1;
 0443                int fromIndex = index - 1;
 444
 445                // If fromIndex and toIndex are the same, it means that "zero bits" are already in the correct place.
 446                // This happens for leading and trailing compression.
 0447                if (fromIndex != toIndex)
 0448                {
 0449                    for (int i = index - compressorIndex; i > 0; --i)
 0450                    {
 0451                        numbers[toIndex--] = numbers[fromIndex];
 0452                        numbers[fromIndex--] = 0;
 0453                    }
 0454                }
 0455            }
 0456        }
 457    }
 458}
 459

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.Uri/src/System/IPv6AddressHelper.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5
 6namespace System.Net
 7{
 8    // The class designed as to keep minimal the working set of Uri class.
 9    // The idea is to stay with static helper methods and strings
 10    internal static partial class IPv6AddressHelper
 11    {
 12        internal static unsafe string ParseCanonicalName(ReadOnlySpan<char> str, ref bool isLoopback, out ReadOnlySpan<c
 013        {
 014            Span<ushort> numbers = stackalloc ushort[NumberOfLabels];
 015            numbers.Clear();
 016            Parse(str, numbers, out scopeId);
 017            isLoopback = IsLoopback(numbers);
 18
 19            // RFC 5952 Sections 4 & 5 - Compressed, lower case, with possible embedded IPv4 addresses.
 20
 21            // Start to finish, inclusive.  <-1, -1> for no compression
 022            (int rangeStart, int rangeEnd) = FindCompressionRange(numbers);
 023            bool ipv4Embedded = ShouldHaveIpv4Embedded(numbers);
 24
 025            Span<char> stackSpace = stackalloc char[48]; // large enough for any IPv6 string, including brackets
 026            stackSpace[0] = '[';
 027            int pos = 1;
 28            int charsWritten;
 29            bool success;
 030            for (int i = 0; i < NumberOfLabels; i++)
 031            {
 032                if (ipv4Embedded && i == (NumberOfLabels - 2))
 033                {
 034                    stackSpace[pos++] = ':';
 35
 36                    // Write the remaining digits as an IPv4 address
 037                    success = (numbers[i] >> 8).TryFormat(stackSpace.Slice(pos), out charsWritten);
 038                    Debug.Assert(success);
 039                    pos += charsWritten;
 40
 041                    stackSpace[pos++] = '.';
 042                    success = (numbers[i] & 0xFF).TryFormat(stackSpace.Slice(pos), out charsWritten);
 043                    Debug.Assert(success);
 044                    pos += charsWritten;
 45
 046                    stackSpace[pos++] = '.';
 047                    success = (numbers[i + 1] >> 8).TryFormat(stackSpace.Slice(pos), out charsWritten);
 048                    Debug.Assert(success);
 049                    pos += charsWritten;
 50
 051                    stackSpace[pos++] = '.';
 052                    success = (numbers[i + 1] & 0xFF).TryFormat(stackSpace.Slice(pos), out charsWritten);
 053                    Debug.Assert(success);
 054                    pos += charsWritten;
 055                    break;
 56                }
 57
 58                // Compression; 1::1, ::1, 1::
 059                if (rangeStart == i)
 060                {
 61                    // Start compression, add :
 062                    stackSpace[pos++] = ':';
 063                }
 64
 065                if (rangeStart <= i && rangeEnd == NumberOfLabels)
 066                {
 67                    // Remainder compressed; 1::
 068                    stackSpace[pos++] = ':';
 069                    break;
 70                }
 71
 072                if (rangeStart <= i && i < rangeEnd)
 073                {
 074                    continue; // Compressed
 75                }
 76
 077                if (i != 0)
 078                {
 079                    stackSpace[pos++] = ':';
 080                }
 081                success = numbers[i].TryFormat(stackSpace.Slice(pos), out charsWritten, format: "x");
 082                Debug.Assert(success);
 083                pos += charsWritten;
 084            }
 85
 086            stackSpace[pos++] = ']';
 087            return new string(stackSpace.Slice(0, pos));
 088        }
 89
 90        private static bool IsLoopback(ReadOnlySpan<ushort> numbers)
 091        {
 92            //
 93            // is the address loopback? Loopback is defined as one of:
 94            //
 95            //  0:0:0:0:0:0:0:1
 96            //  0:0:0:0:0:0:127.0.0.1       == 0:0:0:0:0:0:7F00:0001
 97            //  0:0:0:0:0:FFFF:127.0.0.1    == 0:0:0:0:0:FFFF:7F00:0001
 98            //
 99
 0100            return ((numbers[0] == 0)
 0101                            && (numbers[1] == 0)
 0102                            && (numbers[2] == 0)
 0103                            && (numbers[3] == 0)
 0104                            && (numbers[4] == 0))
 0105                           && (((numbers[5] == 0)
 0106                                && (numbers[6] == 0)
 0107                                && (numbers[7] == 1))
 0108                               || (((numbers[6] == 0x7F00)
 0109                                    && (numbers[7] == 0x0001))
 0110                                   && ((numbers[5] == 0)
 0111                                       || (numbers[5] == 0xFFFF))));
 0112        }
 113
 114        /// <summary>
 115        /// Determine whether a name is a valid IPv6 address. Rules are:
 116        /// <para>*  8 groups of 16-bit hex numbers, separated by ':'</para>
 117        /// <para>*  a *single* run of zeros can be compressed using the symbol '::'</para>
 118        /// <para>*  an optional string of a ScopeID delimited by '%'</para>
 119        /// <para>*  the last 32 bits in an address can be represented as an IPv4 address</para>
 120        /// </summary>
 121        /// <param name="name">The host to validate.</param>
 122        /// <param name="length">The length of the IPv6 address (index of ']' + 1).</param>
 123        /// <remarks>Assumes that the caller already checked that the first character is '['.</remarks>
 124        public static bool IsValid(ReadOnlySpan<char> name, out int length)
 1076125        {
 1076126            Debug.Assert(name.StartsWith('['));
 127
 1076128            length = 0; // Default value in case of failure
 1076129            int sequenceCount = 0;
 1076130            int sequenceLength = 0;
 1076131            bool haveCompressor = false;
 1076132            bool haveIPv4Address = false;
 1076133            bool expectingNumber = true;
 1076134            int lastSequence = 1;
 135
 136            // Starting with a colon character is only valid if another colon follows.
 1076137            if (name.Length < 3 || (name[1] == ':' && name[2] != ':'))
 0138            {
 0139                return false;
 140            }
 141
 142            int i;
 23508143            for (i = 1; i < name.Length; ++i)
 11754144            {
 11754145                if (char.IsAsciiHexDigit(name[i]))
 6484146                {
 6484147                    ++sequenceLength;
 6484148                    expectingNumber = false;
 6484149                }
 150                else
 5270151                {
 5270152                    if (sequenceLength > 4)
 0153                    {
 0154                        return false;
 155                    }
 156
 5270157                    if (sequenceLength != 0)
 3306158                    {
 3306159                        ++sequenceCount;
 3306160                        lastSequence = i - sequenceLength;
 3306161                    }
 162
 5270163                    switch (name[i])
 164                    {
 165                        case '%':
 0166                            while (true)
 0167                            {
 0168                                if (++i == name.Length)
 0169                                {
 170                                    // no closing ']', fail
 0171                                    return false;
 172                                }
 173
 0174                                if (name[i] == ']')
 0175                                {
 0176                                    goto case ']';
 177                                }
 178
 179                                // Our general IPv6 parsing rules are very lenient on the ZoneID.
 180                                // Since this is the logic specific to Uri, we restrict the set of allowed characters (m
 0181                                if (name[i] != '%' && !UriHelper.Unreserved.Contains(name[i]))
 0182                                {
 0183                                    return false;
 184                                }
 0185                            }
 186
 187                        case ']':
 188                            const int ExpectedSequenceCount = 8;
 189
 1076190                            if (!expectingNumber &&
 1076191                                (haveCompressor ? (sequenceCount < ExpectedSequenceCount) : (sequenceCount == ExpectedSe
 1076192                            {
 1076193                                length = i + 1;
 1076194                                return true;
 195                            }
 196
 0197                            return false;
 198
 199                        case ':':
 3992200                            if ((i > 0) && (name[i - 1] == ':'))
 942201                            {
 942202                                if (haveCompressor)
 0203                                {
 204                                    //
 205                                    // can only have one per IPv6 address
 206                                    //
 207
 0208                                    return false;
 209                                }
 942210                                haveCompressor = true;
 942211                                expectingNumber = false;
 942212                            }
 213                            else
 3050214                            {
 3050215                                expectingNumber = true;
 3050216                            }
 3992217                            break;
 218
 219                        case '.':
 202220                            if (haveIPv4Address)
 0221                            {
 0222                                return false;
 223                            }
 224
 202225                            i = name.Length;
 202226                            if (!IPv4AddressHelper.IsValid(name.Slice(lastSequence, i - lastSequence), out int seqEnd, t
 0227                            {
 0228                                return false;
 229                            }
 202230                            i = lastSequence + seqEnd;
 231                            // ipv4 address takes 2 slots in ipv6 address, one was just counted meeting the '.'
 202232                            ++sequenceCount;
 202233                            haveIPv4Address = true;
 202234                            --i;            // it will be incremented back on the next loop
 202235                            break;
 236
 237                        default:
 0238                            return false;
 239                    }
 4194240                    sequenceLength = 0;
 4194241                }
 10678242            }
 243
 0244            return false;
 1076245        }
 246    }
 247}
 248