[PATCH 6/7] ntdll: Implement RtlIpv6AddressToString(Ex)[AW]

Alex Henrie alexhenrie24 at gmail.com
Mon May 25 23:36:23 CDT 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46788
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 dlls/ntdll/ntdll.spec  |   8 +--
 dlls/ntdll/rtl.c       | 129 +++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/tests/rtl.c |  14 +----
 include/ip2string.h    |   7 +++
 4 files changed, 143 insertions(+), 15 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 7ae8a6071d..6bd0a599a9 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -784,10 +784,10 @@
 @ stdcall RtlIpv4StringToAddressExA(str long ptr ptr)
 @ stdcall RtlIpv4StringToAddressExW(wstr long ptr ptr)
 @ stdcall RtlIpv4StringToAddressW(wstr long ptr ptr)
-# @ stub RtlIpv6AddressToStringA
-# @ stub RtlIpv6AddressToStringExA
-# @ stub RtlIpv6AddressToStringExW
-# @ stub RtlIpv6AddressToStringW
+@ stdcall RtlIpv6AddressToStringA(ptr ptr)
+@ stdcall RtlIpv6AddressToStringExA(ptr long long ptr ptr)
+@ stdcall RtlIpv6AddressToStringExW(ptr long long ptr ptr)
+@ stdcall RtlIpv6AddressToStringW(ptr ptr)
 @ stdcall RtlIpv6StringToAddressA(str ptr ptr)
 @ stdcall RtlIpv6StringToAddressExA(str ptr ptr ptr)
 @ stdcall RtlIpv6StringToAddressExW(wstr ptr ptr ptr)
diff --git a/dlls/ntdll/rtl.c b/dlls/ntdll/rtl.c
index 003e4a1b3b..bf91423eba 100644
--- a/dlls/ntdll/rtl.c
+++ b/dlls/ntdll/rtl.c
@@ -1412,6 +1412,135 @@ CHAR * WINAPI RtlIpv4AddressToStringA(const IN_ADDR *pin, LPSTR buffer)
     return buffer + size - 1;
 }
 
+static BOOL is_ipv4_in_ipv6(const IN6_ADDR *address)
+{
+    if (address->s6_words[5] == htons(0x5efe) && (address->s6_words[4] & ~htons(0x200)) == 0)
+        return TRUE;
+    if (*(UINT64 *)address != 0)
+        return FALSE;
+    if (address->s6_words[4] != 0 && address->s6_words[4] != 0xffff)
+        return FALSE;
+    if (address->s6_words[4] == 0 && address->s6_words[5] != 0 && address->s6_words[5] != 0xffff)
+        return FALSE;
+    if (address->s6_words[4] == 0xffff && address->s6_words[5] != 0)
+        return FALSE;
+    if (address->s6_words[6] == 0)
+        return FALSE;
+    return TRUE;
+}
+
+/***********************************************************************
+ * RtlIpv6AddressToStringExA [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlIpv6AddressToStringExA(const IN6_ADDR *address, ULONG scope, USHORT port, char *str, ULONG *size)
+{
+    char buffer[64], *p = buffer;
+    int i, len, gap = -1, gap_len = 1, ipv6_end = 8;
+    ULONG needed;
+    NTSTATUS ret;
+
+    TRACE("(%p %u %u %p %p)\n", address, scope, port, str, size);
+
+    if (!address || !str || !size)
+        return STATUS_INVALID_PARAMETER;
+
+    if (is_ipv4_in_ipv6(address))
+        ipv6_end = 6;
+
+    for (i = 0; i < ipv6_end; i++)
+    {
+        len = 0;
+        while (!address->s6_words[i] && i < ipv6_end)
+        {
+            i++;
+            len++;
+        }
+        if (len > gap_len)
+        {
+            gap = i - len;
+            gap_len = len;
+        }
+    }
+
+    if (port) p += sprintf(p, "[");
+
+    i = 0;
+    while (i < ipv6_end)
+    {
+        if (i == gap)
+        {
+            p += sprintf(p, ":");
+            i += gap_len;
+            if (i == ipv6_end) p += sprintf(p, ":");
+            continue;
+        }
+        if (i > 0) p += sprintf(p, ":");
+        p += sprintf(p, "%x", ntohs(address->s6_words[i]));
+        i++;
+    }
+
+    if (ipv6_end == 6)
+    {
+        if (p[-1] != ':') p += sprintf(p, ":");
+        p = RtlIpv4AddressToStringA((IN_ADDR *)(address->s6_words + 6), p);
+    }
+
+    if (scope) p += sprintf(p, "%%%u", scope);
+
+    if (port) p += sprintf(p, "]:%u", ntohs(port));
+
+    needed = p - buffer + 1;
+
+    if (*size >= needed)
+    {
+        strcpy(str, buffer);
+        ret = STATUS_SUCCESS;
+    }
+    else
+    {
+        ret = STATUS_INVALID_PARAMETER;
+    }
+
+    *size = needed;
+    return ret;
+}
+
+/***********************************************************************
+ * RtlIpv6AddressToStringA [NTDLL.@]
+ */
+char * WINAPI RtlIpv6AddressToStringA(const IN6_ADDR *address, char *str)
+{
+    ULONG size = 46;
+    if (!address || !str) return str - 1;
+    str[45] = 0; /* this byte is set even though the string is always shorter */
+    RtlIpv6AddressToStringExA(address, 0, 0, str, &size);
+    return str + size - 1;
+}
+
+/***********************************************************************
+ * RtlIpv6AddressToStringExW [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlIpv6AddressToStringExW(const IN6_ADDR *address, ULONG scope, USHORT port, WCHAR *str, ULONG *size)
+{
+    char cstr[64];
+    NTSTATUS ret = RtlIpv6AddressToStringExA(address, scope, port, cstr, size);
+    if (ret == STATUS_SUCCESS) RtlMultiByteToUnicodeN(str, *size * sizeof(WCHAR), NULL, cstr, *size);
+    return ret;
+}
+
+/***********************************************************************
+ * RtlIpv6AddressToStringW [NTDLL.@]
+ */
+WCHAR * WINAPI RtlIpv6AddressToStringW(const IN6_ADDR *address, WCHAR *str)
+{
+    ULONG size = 46;
+    if (!address || !str) return str;
+    str[45] = 0; /* this word is set even though the string is always shorter */
+    if (RtlIpv6AddressToStringExW(address, 0, 0, str, &size) != STATUS_SUCCESS)
+        return str;
+    return str + size - 1;
+}
+
 /***********************************************************************
  * get_pointer_obfuscator (internal)
  */
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c
index f83031b490..94c6b582f3 100644
--- a/dlls/ntdll/tests/rtl.c
+++ b/dlls/ntdll/tests/rtl.c
@@ -73,7 +73,6 @@ static DWORD     (WINAPI *pRtlGetThreadErrorMode)(void);
 static NTSTATUS  (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
 static NTSTATUS  (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG);
 static NTSTATUS  (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT);
-static CHAR *    (WINAPI *pRtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
 static NTSTATUS  (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG);
 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressExA)(PCSTR, struct in6_addr *, PULONG, PUSHORT);
 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressExW)(PCWSTR, struct in6_addr *, PULONG, PUSHORT);
@@ -114,7 +113,6 @@ static void InitFunctionPtrs(void)
         pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
         pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA");
         pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA");
-        pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA");
         pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA");
         pRtlIpv6StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExA");
         pRtlIpv6StringToAddressExW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExW");
@@ -1801,22 +1799,16 @@ static void test_RtlIpv6AddressToString(void)
     };
     unsigned int i;
 
-    if (!pRtlIpv6AddressToStringA)
-    {
-        skip("RtlIpv6AddressToStringA not available\n");
-        return;
-    }
-
     memset(buffer, '#', sizeof(buffer));
     buffer[sizeof(buffer)-1] = 0;
     memset(&ip, 0, sizeof(ip));
-    result = pRtlIpv6AddressToStringA(&ip, buffer);
+    result = RtlIpv6AddressToStringA(&ip, buffer);
 
     len = strlen(buffer);
     ok(result == (buffer + len) && !strcmp(buffer, "::"),
        "got %p with '%s' (expected %p with '::')\n", result, buffer, buffer + len);
 
-    result = pRtlIpv6AddressToStringA(&ip, NULL);
+    result = RtlIpv6AddressToStringA(&ip, NULL);
     ok(result == (LPCSTR)~0 || broken(result == (LPCSTR)len) /* WinXP / Win2k3 */,
        "got %p, expected %p\n", result, (LPCSTR)~0);
 
@@ -1826,7 +1818,7 @@ static void test_RtlIpv6AddressToString(void)
         memset(buffer, '#', sizeof(buffer));
         buffer[sizeof(buffer)-1] = 0;
 
-        result = pRtlIpv6AddressToStringA(&ip, buffer);
+        result = RtlIpv6AddressToStringA(&ip, buffer);
         len = strlen(buffer);
         ok(result == (buffer + len) && !strcmp(buffer, tests[i].address),
            "got %p with '%s' (expected %p with '%s')\n", result, buffer, buffer + len, tests[i].address);
diff --git a/include/ip2string.h b/include/ip2string.h
index 4c5f36c15f..84835d4593 100644
--- a/include/ip2string.h
+++ b/include/ip2string.h
@@ -30,6 +30,13 @@ NTSTATUS WINAPI RtlIpv4AddressToStringExA(const IN_ADDR *address, USHORT port, c
 NTSTATUS WINAPI RtlIpv4AddressToStringExW(const IN_ADDR *address, USHORT port, WCHAR *str, ULONG *size);
 #define RtlIpv4AddressToStringEx WINELIB_NAME_AW(RtlIpv4AddressToStringEx)
 
+char * WINAPI RtlIpv6AddressToStringA(const IN6_ADDR *address, char *str);
+WCHAR * WINAPI RtlIpv6AddressToStringW(const IN6_ADDR *address, WCHAR *str);
+#define RtlIpv6AddressToString WINELIB_NAME_AW(RtlIpv6AddressToString)
+NTSTATUS WINAPI RtlIpv6AddressToStringExA(const IN6_ADDR *address, LONG scope, USHORT port, char *str, ULONG *size);
+NTSTATUS WINAPI RtlIpv6AddressToStringExW(const IN6_ADDR *address, LONG scope, USHORT port, WCHAR *str, ULONG *size);
+#define RtlIpv6AddressToStringEx WINELIB_NAME_AW(RtlIpv6AddressToStringEx)
+
 NTSTATUS WINAPI RtlIpv4StringToAddressA(const char *str, BOOLEAN strict, const char **terminator, IN_ADDR *address);
 NTSTATUS WINAPI RtlIpv4StringToAddressW(const WCHAR *str, BOOLEAN strict, const WCHAR **terminator, IN_ADDR *address);
 #define RtlIpv4StringToAddress WINELIB_NAME_AW(RtlIpv4StringToAddress)
-- 
2.26.2




More information about the wine-devel mailing list