ntdll: Implement RtlIpv6StringToAddress(Ex)[AW].

Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alex Henrie 2020-05-13 08:52:52 -06:00 committed by Alexandre Julliard
parent 288515c51f
commit 474d1f0b2d
4 changed files with 222 additions and 17 deletions

View File

@ -784,10 +784,10 @@
# @ stub RtlIpv6AddressToStringExA # @ stub RtlIpv6AddressToStringExA
# @ stub RtlIpv6AddressToStringExW # @ stub RtlIpv6AddressToStringExW
# @ stub RtlIpv6AddressToStringW # @ stub RtlIpv6AddressToStringW
# @ stub RtlIpv6StringToAddressA @ stdcall RtlIpv6StringToAddressA(str ptr ptr)
# @ stub RtlIpv6StringToAddressExA @ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr)
@ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr) @ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
# @ stub RtlIpv6StringToAddressW @ stdcall RtlIpv6StringToAddressW(wstr ptr ptr)
@ stdcall RtlIsActivationContextActive(ptr) @ stdcall RtlIsActivationContextActive(ptr)
@ stdcall RtlIsCriticalSectionLocked(ptr) @ stdcall RtlIsCriticalSectionLocked(ptr)
@ stdcall RtlIsCriticalSectionLockedByThread(ptr) @ stdcall RtlIsCriticalSectionLockedByThread(ptr)

View File

@ -97,6 +97,15 @@ static const DWORD CRC_table[256] =
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
}; };
static const int hex_table[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2F */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5F */
-1, 10, 11, 12, 13, 14, 15 /* 0x60-0x66 */
};
#if defined(_WIN64) && !defined(_MSC_VER) #if defined(_WIN64) && !defined(_MSC_VER)
static inline unsigned char _InterlockedCompareExchange128(__int64 *dest, __int64 xchg_high, __int64 xchg_low, __int64 *compare) static inline unsigned char _InterlockedCompareExchange128(__int64 *dest, __int64 xchg_high, __int64 xchg_low, __int64 *compare)
@ -904,15 +913,6 @@ void WINAPI RtlCopyLuidAndAttributesArray(
static BOOL parse_ipv4_component(const WCHAR **str, BOOL strict, ULONG *value) static BOOL parse_ipv4_component(const WCHAR **str, BOOL strict, ULONG *value)
{ {
static const int hex_table[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2F */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4F */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5F */
-1, 10, 11, 12, 13, 14, 15 /* 0x60-0x66 */
};
int base = 10, d; int base = 10, d;
WCHAR c; WCHAR c;
ULONG cur_value, prev_value = 0; ULONG cur_value, prev_value = 0;
@ -1092,13 +1092,211 @@ NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const c
return ret; return ret;
} }
static BOOL parse_ipv6_component(const WCHAR **str, int base, ULONG *value)
{
WCHAR *terminator;
if (**str >= ARRAY_SIZE(hex_table) || hex_table[**str] == -1) return FALSE;
*value = min(wcstoul(*str, &terminator, base), 0x7FFFFFFF);
if (*terminator == '0') terminator++; /* "0x" but nothing valid after */
else if (terminator == *str) return FALSE;
*str = terminator;
return TRUE;
}
static NTSTATUS ipv6_string_to_address(const WCHAR *str, BOOL ex,
const WCHAR **terminator, IN6_ADDR *address, ULONG *scope, USHORT *port)
{
BOOL expecting_port = FALSE, has_0x = FALSE, too_big = FALSE;
int n_bytes = 0, n_ipv4_bytes = 0, gap = -1;
ULONG ip_component, scope_component = 0, port_component = 0;
const WCHAR *prev_str;
if (str[0] == '[')
{
if (!ex) goto error;
expecting_port = TRUE;
str++;
}
if (str[0] == ':')
{
if (str[1] != ':') goto error;
str++;
/* Windows bug: a double colon at the beginning is treated as 4 bytes of zeros instead of 2 */
address->u.Word[0] = 0;
n_bytes = 2;
}
for (;;)
{
if (!n_ipv4_bytes && *str == ':')
{
/* double colon */
if (gap != -1) goto error;
str++;
prev_str = str;
gap = n_bytes;
if (n_bytes == 14 || !parse_ipv6_component(&str, 16, &ip_component)) break;
str = prev_str;
}
else
{
prev_str = str;
}
if (!n_ipv4_bytes && n_bytes <= (gap != -1 ? 10 : 12))
{
if (parse_ipv6_component(&str, 10, &ip_component) && *str == '.')
n_ipv4_bytes = 1;
str = prev_str;
}
if (n_ipv4_bytes)
{
/* IPv4 component */
if (!parse_ipv6_component(&str, 10, &ip_component)) goto error;
if (str - prev_str > 3 || ip_component > 255)
{
too_big = TRUE;
}
else
{
if (*str != '.' && (n_ipv4_bytes < 4 || (n_bytes < 15 && gap == -1))) goto error;
address->u.Byte[n_bytes] = ip_component;
n_bytes++;
}
if (n_ipv4_bytes == 4 || *str != '.') break;
n_ipv4_bytes++;
}
else
{
/* IPv6 component */
if (!parse_ipv6_component(&str, 16, &ip_component)) goto error;
if (prev_str[0] == '0' && (prev_str[1] == 'x' || prev_str[1] == 'X'))
{
/* Windows "feature": the last IPv6 component can start with "0x" and be longer than 4 digits */
if (terminator) *terminator = prev_str + 1; /* Windows says that the "x" is the terminator */
if (n_bytes < 14 && gap == -1) return STATUS_INVALID_PARAMETER;
address->u.Word[n_bytes/2] = htons(ip_component);
n_bytes += 2;
has_0x = TRUE;
goto fill_gap;
}
if (*str != ':' && n_bytes < 14 && gap == -1) goto error;
if (str - prev_str > 4)
too_big = TRUE;
else
address->u.Word[n_bytes/2] = htons(ip_component);
n_bytes += 2;
if (*str != ':' || (gap != -1 && str[1] == ':')) break;
}
if (n_bytes == (gap != -1 ? 14 : 16)) break;
if (too_big) return STATUS_INVALID_PARAMETER;
str++;
}
if (terminator) *terminator = str;
if (too_big) return STATUS_INVALID_PARAMETER;
fill_gap:
if (gap == -1)
{
if (n_bytes < 16) goto error;
}
else
{
memmove(address->u.Byte + 16 - (n_bytes - gap), address->u.Byte + gap, n_bytes - gap);
memset(address->u.Byte + gap, 0, 16 - n_bytes);
}
if (ex)
{
if (has_0x) goto error;
if (*str == '%')
{
str++;
if (!parse_ipv4_component(&str, TRUE, &scope_component)) goto error;
}
if (expecting_port)
{
if (*str != ']') goto error;
str++;
if (*str == ':')
{
str++;
if (!parse_ipv4_component(&str, FALSE, &port_component)) goto error;
if (!port_component || port_component > 0xFFFF || *str) goto error;
port_component = htons(port_component);
}
}
}
if (!terminator && *str) return STATUS_INVALID_PARAMETER;
if (scope) *scope = scope_component;
if (port) *port = port_component;
return STATUS_SUCCESS;
error:
if (terminator) *terminator = str;
return STATUS_INVALID_PARAMETER;
}
/*********************************************************************** /***********************************************************************
* RtlIpv6StringToAddressExW [NTDLL.@] * RtlIpv6StringToAddressExW [NTDLL.@]
*/ */
NTSTATUS NTAPI RtlIpv6StringToAddressExW(const WCHAR *str, IN6_ADDR *address, ULONG *scope, USHORT *port) NTSTATUS NTAPI RtlIpv6StringToAddressExW(const WCHAR *str, IN6_ADDR *address, ULONG *scope, USHORT *port)
{ {
FIXME("(%s, %p, %p, %p): stub\n", debugstr_w(str), address, scope, port); TRACE("(%s, %p, %p, %p)\n", debugstr_w(str), address, scope, port);
return STATUS_NOT_IMPLEMENTED; if (!str || !address || !scope || !port) return STATUS_INVALID_PARAMETER;
return ipv6_string_to_address(str, TRUE, NULL, address, scope, port);
}
/***********************************************************************
* RtlIpv6StringToAddressW [NTDLL.@]
*/
NTSTATUS WINAPI RtlIpv6StringToAddressW(const WCHAR *str, const WCHAR **terminator, IN6_ADDR *address)
{
TRACE("(%s, %p, %p)\n", debugstr_w(str), terminator, address);
return ipv6_string_to_address(str, FALSE, terminator, address, NULL, NULL);
}
/***********************************************************************
* RtlIpv6StringToAddressExA [NTDLL.@]
*/
NTSTATUS WINAPI RtlIpv6StringToAddressExA(const char *str, IN6_ADDR *address, ULONG *scope, USHORT *port)
{
WCHAR wstr[64];
TRACE("(%s, %p, %p, %p)\n", debugstr_a(str), address, scope, port);
if (!str || !address || !scope || !port)
return STATUS_INVALID_PARAMETER;
RtlMultiByteToUnicodeN(wstr, sizeof(wstr), NULL, str, strlen(str) + 1);
wstr[ARRAY_SIZE(wstr) - 1] = 0;
return ipv6_string_to_address(wstr, TRUE, NULL, address, scope, port);
}
/***********************************************************************
* RtlIpv6StringToAddressA [NTDLL.@]
*/
NTSTATUS WINAPI RtlIpv6StringToAddressA(const char *str, const char **terminator, IN6_ADDR *address)
{
WCHAR wstr[64];
const WCHAR *wterminator = NULL;
NTSTATUS ret;
TRACE("(%s, %p, %p)\n", debugstr_a(str), terminator, address);
RtlMultiByteToUnicodeN(wstr, sizeof(wstr), NULL, str, strlen(str) + 1);
wstr[ARRAY_SIZE(wstr) - 1] = 0;
ret = ipv6_string_to_address(wstr, FALSE, &wterminator, address, NULL, NULL);
if (terminator && wterminator) *terminator = str + (wterminator - wstr);
return ret;
} }
/*********************************************************************** /***********************************************************************

View File

@ -1136,10 +1136,10 @@
@ stub RtlIpv6AddressToStringExA @ stub RtlIpv6AddressToStringExA
@ stub RtlIpv6AddressToStringExW @ stub RtlIpv6AddressToStringExW
@ stub RtlIpv6AddressToStringW @ stub RtlIpv6AddressToStringW
@ stub RtlIpv6StringToAddressA @ stdcall RtlIpv6StringToAddressA(str ptr ptr) ntdll.RtlIpv6StringToAddressA
@ stub RtlIpv6StringToAddressExA @ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr) ntdll.RtlIpv6StringToAddressExA
@ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr) @ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
@ stub RtlIpv6StringToAddressW @ stdcall RtlIpv6StringToAddressW(wstr ptr ptr) ntdll.RtlIpv6StringToAddressW
@ stub RtlIsGenericTableEmpty @ stub RtlIsGenericTableEmpty
@ stub RtlIsGenericTableEmptyAvl @ stub RtlIsGenericTableEmptyAvl
@ stdcall RtlIsNameLegalDOS8Dot3(ptr ptr ptr) @ stdcall RtlIsNameLegalDOS8Dot3(ptr ptr ptr)

View File

@ -30,6 +30,13 @@ NTSTATUS WINAPI RtlIpv4StringToAddressExA(const char *str, BOOLEAN strict, IN_AD
NTSTATUS WINAPI RtlIpv4StringToAddressExW(const WCHAR *str, BOOLEAN strict, IN_ADDR *address, USHORT *port); NTSTATUS WINAPI RtlIpv4StringToAddressExW(const WCHAR *str, BOOLEAN strict, IN_ADDR *address, USHORT *port);
#define RtlIpv4StringToAddressEx WINELIB_NAME_AW(RtlIpv4StringToAddressEx) #define RtlIpv4StringToAddressEx WINELIB_NAME_AW(RtlIpv4StringToAddressEx)
NTSTATUS WINAPI RtlIpv6StringToAddressA(const char *str, const char **terminator, IN6_ADDR *address);
NTSTATUS WINAPI RtlIpv6StringToAddressW(const WCHAR *str, const WCHAR **terminator, IN6_ADDR *address);
#define RtlIpv6StringToAddress WINELIB_NAME_AW(RtlIpv6StringToAddress)
NTSTATUS WINAPI RtlIpv6StringToAddressExA(const char *str, IN6_ADDR *address, ULONG *scope, USHORT *port);
NTSTATUS WINAPI RtlIpv6StringToAddressExW(const WCHAR *str, IN6_ADDR *address, ULONG *scope, USHORT *port);
#define RtlIpv6StringToAddressEx WINELIB_NAME_AW(RtlIpv6StringToAddressEx)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif