//
// Parse
//
// Convert this IPv6 address into a sequence of 8 16-bit numbers
//
// Inputs:
// <member> Name
// The validated IPv6 address
//
// Outputs:
// <member> numbers
// Array filled in with the numbers in the IPv6 groups
//
// <member> PrefixLength
// Set to the number after the prefix separator (/) if found
//
// Assumes:
// <Name> has been validated and contains only hex digits in groups of
// 16-bit numbers, the characters ':' and '/', and a possible IPv4
// address
//
// Returns:
// true if this is a loopback, false otherwise. There is no failure indication as the sting must be a valid one.
//
// Throws:
// Nothing
//
internal static unsafe bool Parse(string address, ushort *numbers, int start, ref string scopeId)
{
int number = 0;
int index = 0;
int compressorIndex = -1;
bool numberIsValid = true;
//This used to be a class instance member but have not been used so far
int PrefixLength = 0;
if (address[start] == '[')
{
++start;
}
for (int i = start; i < address.Length && address[i] != ']';)
{
switch (address[i])
{
case '%':
if (numberIsValid)
{
numbers[index++] = (ushort)number;
numberIsValid = false;
}
start = i;
for (++i; address[i] != ']' && address[i] != '/'; ++i)
{
;
}
scopeId = address.Substring(start, i - start);
// ignore prefix if any
for (; address[i] != ']'; ++i)
{
;
}
break;
case ':':
numbers[index++] = (ushort)number;
number = 0;
++i;
if (address[i] == ':')
{
compressorIndex = index;
++i;
}
else if ((compressorIndex < 0) && (index < 6))
{
//
// no point checking for IPv4 address if we don't
// have a compressor or we haven't seen 6 16-bit
// numbers yet
//
break;
}
//
// check to see if the upcoming number is really an IPv4
// address. If it is, convert it to 2 ushort numbers
//
for (int j = i; (address[j] != ']') &&
(address[j] != ':') &&
(address[j] != '%') &&
(address[j] != '/') &&
(j < i + 4); ++j)
{
if (address[j] == '.')
{
//
// we have an IPv4 address. Find the end of it:
// we know that since we have a valid IPv6
// address, the only things that will terminate
// the IPv4 address are the prefix delimiter '/'
// or the end-of-string (which we conveniently
// delimited with ']')
//
while ((address[j] != ']') && (address[j] != '/') && (address[j] != '%'))
{
++j;
}
number = IPv4AddressHelper.ParseHostNumber(address, i, j);
unchecked
{
numbers[index++] = (ushort)(number >> 16);
numbers[index++] = (ushort)number;
}
i = j;
//
// set this to avoid adding another number to
// the array if there's a prefix
//
number = 0;
numberIsValid = false;
break;
}
}
break;
case '/':
if (numberIsValid)
{
numbers[index++] = (ushort)number;
numberIsValid = false;
}
//
// since we have a valid IPv6 address string, the prefix
// length is the last token in the string
//
for (++i; address[i] != ']'; ++i)
{
PrefixLength = PrefixLength * 10 + (address[i] - '0');
}
break;
default:
number = number * 16 + Uri.FromHex(address[i++]);
break;
}
}
//
// add number to the array if its not the prefix length or part of
// an IPv4 address that's already been handled
//
if (numberIsValid)
{
numbers[index++] = (ushort)number;
}
//
// if we had a compressor sequence ("::") then we need to expand the
// numbers array
//
if (compressorIndex > 0)
{
int toIndex = NumberOfLabels - 1;
int fromIndex = index - 1;
for (int i = index - compressorIndex; i > 0; --i)
{
numbers[toIndex--] = numbers[fromIndex];
numbers[fromIndex--] = 0;
}
}
//
// is the address loopback? Loopback is defined as one of:
//
// 0:0:0:0:0:0:0:1
// 0:0:0:0:0:0:127.0.0.1 == 0:0:0:0:0:0:7F00:0001
// 0:0:0:0:0:FFFF:127.0.0.1 == 0:0:0:0:0:FFFF:7F00:0001
//
return(((numbers[0] == 0) &&
(numbers[1] == 0) &&
(numbers[2] == 0) &&
(numbers[3] == 0) &&
(numbers[4] == 0)) &&
(((numbers[5] == 0) &&
(numbers[6] == 0) &&
(numbers[7] == 1)) ||
(((numbers[6] == 0x7F00) &&
(numbers[7] == 0x0001)) &&
((numbers[5] == 0) ||
(numbers[5] == 0xFFFF)))));
}