mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
284 lines
10 KiB
Diff
284 lines
10 KiB
Diff
From f2ecf7649cac98316c6e7345c78c66b7afce4b27 Mon Sep 17 00:00:00 2001
|
|
From: Alex Henrie <alexhenrie24@gmail.com>
|
|
Date: Tue, 7 Apr 2020 21:22:52 -0600
|
|
Subject: [PATCH] ntdll: Implement RtlIpv6StringToAddress(Ex)[AW]
|
|
|
|
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
|
|
---
|
|
dlls/ntdll/ntdll.spec | 6 +-
|
|
dlls/ntdll/rtl.c | 221 +++++++++++++++++++++++++++++++++++++++---
|
|
2 files changed, 213 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
|
|
index e61a2578da..b887e82b47 100644
|
|
--- a/dlls/ntdll/ntdll.spec
|
|
+++ b/dlls/ntdll/ntdll.spec
|
|
@@ -781,10 +781,10 @@
|
|
# @ stub RtlIpv6AddressToStringExA
|
|
# @ stub RtlIpv6AddressToStringExW
|
|
# @ stub RtlIpv6AddressToStringW
|
|
-# @ stub RtlIpv6StringToAddressA
|
|
-# @ stub RtlIpv6StringToAddressExA
|
|
+@ stdcall RtlIpv6StringToAddressA(str ptr ptr)
|
|
+@ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr)
|
|
@ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
|
|
-# @ stub RtlIpv6StringToAddressW
|
|
+@ stdcall RtlIpv6StringToAddressW(wstr ptr ptr)
|
|
@ stdcall RtlIsActivationContextActive(ptr)
|
|
@ stdcall RtlIsCriticalSectionLocked(ptr)
|
|
@ stdcall RtlIsCriticalSectionLockedByThread(ptr)
|
|
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
|
|
index 64853369a3..a4e220bcf2 100644
|
|
--- a/dlls/ntdll/rtl.c
|
|
+++ b/dlls/ntdll/rtl.c
|
|
@@ -97,6 +97,16 @@ static const DWORD CRC_table[256] =
|
|
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 */
|
|
+};
|
|
+
|
|
/*
|
|
* resource functions
|
|
*/
|
|
@@ -885,15 +895,6 @@ void WINAPI RtlCopyLuidAndAttributesArray(
|
|
|
|
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;
|
|
WCHAR c;
|
|
ULONG cur_value, prev_value = 0;
|
|
@@ -1073,13 +1074,211 @@ NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const c
|
|
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.@]
|
|
*/
|
|
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);
|
|
- return STATUS_NOT_IMPLEMENTED;
|
|
+ TRACE("(%s, %p, %p, %p)\n", debugstr_w(str), address, scope, port);
|
|
+ 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;
|
|
}
|
|
|
|
/***********************************************************************
|
|
--
|
|
2.26.0
|
|
|