[NTDLL_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / rostests / winetests / ntdll / rtl.c
1 /* Unit test suite for Rtl* API functions
2 *
3 * Copyright 2003 Thomas Mertes
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 * NOTES
20 * We use function pointers here as there is no import library for NTDLL on
21 * windows.
22 */
23
24 #include <stdlib.h>
25
26 #include "ntdll_test.h"
27 #include "inaddr.h"
28 #include "in6addr.h"
29
30 #ifndef __WINE_WINTERNL_H
31
32 typedef struct _RTL_HANDLE
33 {
34 struct _RTL_HANDLE * Next;
35 } RTL_HANDLE;
36
37 typedef struct _RTL_HANDLE_TABLE
38 {
39 ULONG MaxHandleCount;
40 ULONG HandleSize;
41 ULONG Unused[2];
42 PVOID NextFree;
43 PVOID FirstHandle;
44 PVOID ReservedMemory;
45 PVOID MaxHandle;
46 } RTL_HANDLE_TABLE;
47
48 #endif
49
50 /* avoid #include <winsock2.h> */
51 #undef htons
52 #ifdef WORDS_BIGENDIAN
53 #define htons(s) ((USHORT)(s))
54 #else /* WORDS_BIGENDIAN */
55 static inline USHORT __my_ushort_swap(USHORT s)
56 {
57 return (s >> 8) | (s << 8);
58 }
59 #define htons(s) __my_ushort_swap(s)
60 #endif /* WORDS_BIGENDIAN */
61
62
63
64 /* Function ptrs for ntdll calls */
65 static HMODULE hntdll = 0;
66 static PVOID (WINAPI *pWinSqmStartSession)(PVOID unknown1, DWORD unknown2, DWORD unknown3);
67 static BOOL (WINAPI *pWinSqmIsOptedIn)(void);
68 static NTSTATUS (WINAPI *pWinSqmEndSession)(PVOID unknown1);
69 static SIZE_T (WINAPI *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T);
70 static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG);
71 static NTSTATUS (WINAPI *pRtlDeleteTimer)(HANDLE, HANDLE, HANDLE);
72 static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T);
73 static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE);
74 static VOID (WINAPI *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG);
75 static VOID (WINAPI *pRtlZeroMemory)(LPVOID,SIZE_T);
76 static ULONGLONG (WINAPIV *pRtlUlonglongByteSwap)(ULONGLONG source);
77 static ULONG (WINAPI *pRtlUniform)(PULONG);
78 static ULONG (WINAPI *pRtlRandom)(PULONG);
79 static BOOLEAN (WINAPI *pRtlAreAllAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
80 static BOOLEAN (WINAPI *pRtlAreAnyAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
81 static DWORD (WINAPI *pRtlComputeCrc32)(DWORD,const BYTE*,INT);
82 static void (WINAPI * pRtlInitializeHandleTable)(ULONG, ULONG, RTL_HANDLE_TABLE *);
83 static BOOLEAN (WINAPI * pRtlIsValidIndexHandle)(const RTL_HANDLE_TABLE *, ULONG, RTL_HANDLE **);
84 static NTSTATUS (WINAPI * pRtlDestroyHandleTable)(RTL_HANDLE_TABLE *);
85 static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *);
86 static BOOLEAN (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
87 static NTSTATUS (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
88 static NTSTATUS (WINAPI *pRtlFreeSid)(PSID);
89 static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
90 static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
91 static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
92 static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR);
93 static CHAR * (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR);
94 static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG);
95 static NTSTATUS (WINAPI *pRtlIpv4StringToAddressA)(PCSTR, BOOLEAN, PCSTR *, IN_ADDR *);
96 static NTSTATUS (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT);
97 static CHAR * (WINAPI *pRtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
98 static NTSTATUS (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG);
99 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressA)(PCSTR, PCSTR *, struct in6_addr *);
100 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressW)(PCWSTR, PCWSTR *, struct in6_addr *);
101 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExA)(PCSTR, struct in6_addr *, PULONG, PUSHORT);
102 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExW)(PCWSTR, struct in6_addr *, PULONG, PUSHORT);
103 static NTSTATUS (WINAPI *pLdrAddRefDll)(ULONG, HMODULE);
104 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG*, ULONG_PTR*);
105 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
106 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)(LPWSTR, DWORD, LPDWORD, LPCSTR, DWORD);
107 static NTSTATUS (WINAPI *pRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULONG);
108 static NTSTATUS (WINAPI *pRtlDecompressBuffer)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, PULONG);
109 static NTSTATUS (WINAPI *pRtlDecompressFragment)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, ULONG, PULONG, PVOID);
110 static NTSTATUS (WINAPI *pRtlCompressBuffer)(USHORT, const UCHAR*, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID);
111 static BOOL (WINAPI *pRtlIsCriticalSectionLocked)(RTL_CRITICAL_SECTION *);
112 static BOOL (WINAPI *pRtlIsCriticalSectionLockedByThread)(RTL_CRITICAL_SECTION *);
113
114 static HMODULE hkernel32 = 0;
115 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
116
117
118 #define LEN 16
119 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
120 static ULONG src_aligned_block[4];
121 static ULONG dest_aligned_block[32];
122 static const char *src = (const char*)src_aligned_block;
123 static char* dest = (char*)dest_aligned_block;
124
125 static void InitFunctionPtrs(void)
126 {
127 hntdll = LoadLibraryA("ntdll.dll");
128 ok(hntdll != 0, "LoadLibrary failed\n");
129 if (hntdll) {
130 pWinSqmStartSession = (void *)GetProcAddress(hntdll, "WinSqmStartSession");
131 pWinSqmIsOptedIn = (void *)GetProcAddress(hntdll, "WinSqmIsOptedIn");
132 pWinSqmEndSession = (void *)GetProcAddress(hntdll, "WinSqmEndSession");
133 pRtlCompareMemory = (void *)GetProcAddress(hntdll, "RtlCompareMemory");
134 pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong");
135 pRtlDeleteTimer = (void *)GetProcAddress(hntdll, "RtlDeleteTimer");
136 pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory");
137 pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory");
138 pRtlFillMemoryUlong = (void *)GetProcAddress(hntdll, "RtlFillMemoryUlong");
139 pRtlZeroMemory = (void *)GetProcAddress(hntdll, "RtlZeroMemory");
140 pRtlUlonglongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlonglongByteSwap");
141 pRtlUniform = (void *)GetProcAddress(hntdll, "RtlUniform");
142 pRtlRandom = (void *)GetProcAddress(hntdll, "RtlRandom");
143 pRtlAreAllAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAllAccessesGranted");
144 pRtlAreAnyAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAnyAccessesGranted");
145 pRtlComputeCrc32 = (void *)GetProcAddress(hntdll, "RtlComputeCrc32");
146 pRtlInitializeHandleTable = (void *)GetProcAddress(hntdll, "RtlInitializeHandleTable");
147 pRtlIsValidIndexHandle = (void *)GetProcAddress(hntdll, "RtlIsValidIndexHandle");
148 pRtlDestroyHandleTable = (void *)GetProcAddress(hntdll, "RtlDestroyHandleTable");
149 pRtlAllocateHandle = (void *)GetProcAddress(hntdll, "RtlAllocateHandle");
150 pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
151 pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid");
152 pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid");
153 pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb");
154 pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode");
155 pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
156 pLdrProcessRelocationBlock = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock");
157 pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA");
158 pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA");
159 pRtlIpv4StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressA");
160 pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA");
161 pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA");
162 pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA");
163 pRtlIpv6StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressA");
164 pRtlIpv6StringToAddressW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressW");
165 pRtlIpv6StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExA");
166 pRtlIpv6StringToAddressExW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExW");
167 pLdrAddRefDll = (void *)GetProcAddress(hntdll, "LdrAddRefDll");
168 pLdrLockLoaderLock = (void *)GetProcAddress(hntdll, "LdrLockLoaderLock");
169 pLdrUnlockLoaderLock = (void *)GetProcAddress(hntdll, "LdrUnlockLoaderLock");
170 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll, "RtlMultiByteToUnicodeN");
171 pRtlGetCompressionWorkSpaceSize = (void *)GetProcAddress(hntdll, "RtlGetCompressionWorkSpaceSize");
172 pRtlDecompressBuffer = (void *)GetProcAddress(hntdll, "RtlDecompressBuffer");
173 pRtlDecompressFragment = (void *)GetProcAddress(hntdll, "RtlDecompressFragment");
174 pRtlCompressBuffer = (void *)GetProcAddress(hntdll, "RtlCompressBuffer");
175 pRtlIsCriticalSectionLocked = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLocked");
176 pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread");
177 }
178 hkernel32 = LoadLibraryA("kernel32.dll");
179 ok(hkernel32 != 0, "LoadLibrary failed\n");
180 if (hkernel32) {
181 pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
182 }
183 strcpy((char*)src_aligned_block, src_src);
184 ok(strlen(src) == 15, "Source must be 16 bytes long!\n");
185 }
186
187 #ifdef __i386__
188 const char stdcall3_thunk[] =
189 "\x56" /* push %esi */
190 "\x89\xE6" /* mov %esp, %esi */
191 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
192 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
193 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
194 "\xFF\x54\x24\x14" /* calll 20(%esp) */
195 "\x89\xF0" /* mov %esi, %eax */
196 "\x29\xE0" /* sub %esp, %eax */
197 "\x89\xF4" /* mov %esi, %esp */
198 "\x5E" /* pop %esi */
199 "\xC2\x10\x00" /* ret $16 */
200 ;
201
202 static INT (WINAPI *call_stdcall_func3)(PVOID func, PVOID arg0, DWORD arg1, DWORD arg2) = NULL;
203
204 static void test_WinSqm(void)
205 {
206 INT args;
207
208 if (!pWinSqmStartSession)
209 {
210 win_skip("WinSqmStartSession() is not available\n");
211 return;
212 }
213
214 call_stdcall_func3 = (void*) VirtualAlloc( NULL, sizeof(stdcall3_thunk) - 1, MEM_COMMIT,
215 PAGE_EXECUTE_READWRITE );
216 memcpy( call_stdcall_func3, stdcall3_thunk, sizeof(stdcall3_thunk) - 1 );
217
218 args = 3 - call_stdcall_func3( pWinSqmStartSession, NULL, 0, 0 ) / 4;
219 ok(args == 3, "WinSqmStartSession expected to take %d arguments instead of 3\n", args);
220 args = 3 - call_stdcall_func3( pWinSqmIsOptedIn, NULL, 0, 0 ) / 4;
221 ok(args == 0, "WinSqmIsOptedIn expected to take %d arguments instead of 0\n", args);
222 args = 3 - call_stdcall_func3( pWinSqmEndSession, NULL, 0, 0 ) / 4;
223 ok(args == 1, "WinSqmEndSession expected to take %d arguments instead of 1\n", args);
224
225 VirtualFree( call_stdcall_func3, 0, MEM_RELEASE );
226 }
227 #endif
228
229 #define COMP(str1,str2,cmplen,len) size = pRtlCompareMemory(str1, str2, cmplen); \
230 ok(size == len, "Expected %ld, got %ld\n", size, (SIZE_T)len)
231
232 static void test_RtlCompareMemory(void)
233 {
234 SIZE_T size;
235
236 if (!pRtlCompareMemory)
237 {
238 win_skip("RtlCompareMemory is not available\n");
239 return;
240 }
241
242 strcpy(dest, src);
243
244 COMP(src,src,0,0);
245 COMP(src,src,LEN,LEN);
246 dest[0] = 'x';
247 COMP(src,dest,LEN,0);
248 }
249
250 static void test_RtlCompareMemoryUlong(void)
251 {
252 ULONG a[10];
253 ULONG result;
254
255 if (!pRtlCompareMemoryUlong)
256 {
257 win_skip("RtlCompareMemoryUlong is not available\n");
258 return;
259 }
260
261 a[0]= 0x0123;
262 a[1]= 0x4567;
263 a[2]= 0x89ab;
264 a[3]= 0xcdef;
265 result = pRtlCompareMemoryUlong(a, 0, 0x0123);
266 ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %u, expected 0\n", a, result);
267 result = pRtlCompareMemoryUlong(a, 3, 0x0123);
268 ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
269 result = pRtlCompareMemoryUlong(a, 4, 0x0123);
270 ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
271 result = pRtlCompareMemoryUlong(a, 5, 0x0123);
272 ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
273 result = pRtlCompareMemoryUlong(a, 7, 0x0123);
274 ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
275 result = pRtlCompareMemoryUlong(a, 8, 0x0123);
276 ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 4\n", a, result);
277 result = pRtlCompareMemoryUlong(a, 9, 0x0123);
278 ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 4\n", a, result);
279 result = pRtlCompareMemoryUlong(a, 4, 0x0127);
280 ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %u, expected 0\n", a, result);
281 result = pRtlCompareMemoryUlong(a, 4, 0x7123);
282 ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %u, expected 0\n", a, result);
283 result = pRtlCompareMemoryUlong(a, 16, 0x4567);
284 ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %u, expected 0\n", a, result);
285
286 a[1]= 0x0123;
287 result = pRtlCompareMemoryUlong(a, 3, 0x0123);
288 ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
289 result = pRtlCompareMemoryUlong(a, 4, 0x0123);
290 ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
291 result = pRtlCompareMemoryUlong(a, 5, 0x0123);
292 ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
293 result = pRtlCompareMemoryUlong(a, 7, 0x0123);
294 ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
295 result = pRtlCompareMemoryUlong(a, 8, 0x0123);
296 ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 8\n", a, result);
297 result = pRtlCompareMemoryUlong(a, 9, 0x0123);
298 ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 8\n", a, result);
299 }
300
301 #define COPY(len) memset(dest,0,sizeof(dest_aligned_block)); pRtlMoveMemory(dest, src, len)
302 #define CMP(str) ok(strcmp(dest,str) == 0, "Expected '%s', got '%s'\n", str, dest)
303
304 static void test_RtlMoveMemory(void)
305 {
306 if (!pRtlMoveMemory)
307 {
308 win_skip("RtlMoveMemory is not available\n");
309 return;
310 }
311
312 /* Length should be in bytes and not rounded. Use strcmp to ensure we
313 * didn't write past the end (it checks for the final NUL left by memset)
314 */
315 COPY(0); CMP("");
316 COPY(1); CMP("T");
317 COPY(2); CMP("Th");
318 COPY(3); CMP("Thi");
319 COPY(4); CMP("This");
320 COPY(5); CMP("This ");
321 COPY(6); CMP("This i");
322 COPY(7); CMP("This is");
323 COPY(8); CMP("This is ");
324 COPY(9); CMP("This is a");
325
326 /* Overlapping */
327 strcpy(dest, src); pRtlMoveMemory(dest, dest + 1, strlen(src) - 1);
328 CMP("his is a test!!");
329 strcpy(dest, src); pRtlMoveMemory(dest + 1, dest, strlen(src));
330 CMP("TThis is a test!");
331 }
332
333 #define FILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemory(dest,len,'x')
334
335 static void test_RtlFillMemory(void)
336 {
337 if (!pRtlFillMemory)
338 {
339 win_skip("RtlFillMemory is not available\n");
340 return;
341 }
342
343 /* Length should be in bytes and not rounded. Use strcmp to ensure we
344 * didn't write past the end (the remainder of the string should match)
345 */
346 FILL(0); CMP("This is a test!");
347 FILL(1); CMP("xhis is a test!");
348 FILL(2); CMP("xxis is a test!");
349 FILL(3); CMP("xxxs is a test!");
350 FILL(4); CMP("xxxx is a test!");
351 FILL(5); CMP("xxxxxis a test!");
352 FILL(6); CMP("xxxxxxs a test!");
353 FILL(7); CMP("xxxxxxx a test!");
354 FILL(8); CMP("xxxxxxxxa test!");
355 FILL(9); CMP("xxxxxxxxx test!");
356 }
357
358 #define LFILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemoryUlong(dest,len,val)
359
360 static void test_RtlFillMemoryUlong(void)
361 {
362 ULONG val = ('x' << 24) | ('x' << 16) | ('x' << 8) | 'x';
363 if (!pRtlFillMemoryUlong)
364 {
365 win_skip("RtlFillMemoryUlong is not available\n");
366 return;
367 }
368
369 /* Length should be in bytes and not rounded. Use strcmp to ensure we
370 * didn't write past the end (the remainder of the string should match)
371 */
372 LFILL(0); CMP("This is a test!");
373 LFILL(1); CMP("This is a test!");
374 LFILL(2); CMP("This is a test!");
375 LFILL(3); CMP("This is a test!");
376 LFILL(4); CMP("xxxx is a test!");
377 LFILL(5); CMP("xxxx is a test!");
378 LFILL(6); CMP("xxxx is a test!");
379 LFILL(7); CMP("xxxx is a test!");
380 LFILL(8); CMP("xxxxxxxxa test!");
381 LFILL(9); CMP("xxxxxxxxa test!");
382 }
383
384 #define ZERO(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlZeroMemory(dest,len)
385 #define MCMP(str) ok(memcmp(dest,str,LEN) == 0, "Memcmp failed\n")
386
387 static void test_RtlZeroMemory(void)
388 {
389 if (!pRtlZeroMemory)
390 {
391 win_skip("RtlZeroMemory is not available\n");
392 return;
393 }
394
395 /* Length should be in bytes and not rounded. */
396 ZERO(0); MCMP("This is a test!");
397 ZERO(1); MCMP("\0his is a test!");
398 ZERO(2); MCMP("\0\0is is a test!");
399 ZERO(3); MCMP("\0\0\0s is a test!");
400 ZERO(4); MCMP("\0\0\0\0 is a test!");
401 ZERO(5); MCMP("\0\0\0\0\0is a test!");
402 ZERO(6); MCMP("\0\0\0\0\0\0s a test!");
403 ZERO(7); MCMP("\0\0\0\0\0\0\0 a test!");
404 ZERO(8); MCMP("\0\0\0\0\0\0\0\0a test!");
405 ZERO(9); MCMP("\0\0\0\0\0\0\0\0\0 test!");
406 }
407
408 static void test_RtlUlonglongByteSwap(void)
409 {
410 ULONGLONG result;
411
412 if ( !pRtlUlonglongByteSwap )
413 {
414 win_skip("RtlUlonglongByteSwap is not available\n");
415 return;
416 }
417
418 if ( pRtlUlonglongByteSwap( 0 ) != 0 )
419 {
420 win_skip("Broken RtlUlonglongByteSwap in win2k\n");
421 return;
422 }
423
424 result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 );
425 ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result,
426 "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n",
427 (DWORD)(result >> 32), (DWORD)result);
428 }
429
430
431 static void test_RtlUniform(void)
432 {
433 ULONGLONG num;
434 ULONG seed;
435 ULONG seed_bak;
436 ULONG expected;
437 ULONG result;
438
439 if (!pRtlUniform)
440 {
441 win_skip("RtlUniform is not available\n");
442 return;
443 }
444
445 /*
446 * According to the documentation RtlUniform is using D.H. Lehmer's 1948
447 * algorithm. This algorithm is:
448 *
449 * seed = (seed * const_1 + const_2) % const_3;
450 *
451 * According to the documentation the random number is distributed over
452 * [0..MAXLONG]. Therefore const_3 is MAXLONG + 1:
453 *
454 * seed = (seed * const_1 + const_2) % (MAXLONG + 1);
455 *
456 * Because MAXLONG is 0x7fffffff (and MAXLONG + 1 is 0x80000000) the
457 * algorithm can be expressed without division as:
458 *
459 * seed = (seed * const_1 + const_2) & MAXLONG;
460 *
461 * To find out const_2 we just call RtlUniform with seed set to 0:
462 */
463 seed = 0;
464 expected = 0x7fffffc3;
465 result = pRtlUniform(&seed);
466 ok(result == expected,
467 "RtlUniform(&seed (seed == 0)) returns %x, expected %x\n",
468 result, expected);
469 /*
470 * The algorithm is now:
471 *
472 * seed = (seed * const_1 + 0x7fffffc3) & MAXLONG;
473 *
474 * To find out const_1 we can use:
475 *
476 * const_1 = RtlUniform(1) - 0x7fffffc3;
477 *
478 * If that does not work a search loop can try all possible values of
479 * const_1 and compare to the result to RtlUniform(1).
480 * This way we find out that const_1 is 0xffffffed.
481 *
482 * For seed = 1 the const_2 is 0x7fffffc4:
483 */
484 seed = 1;
485 expected = seed * 0xffffffed + 0x7fffffc3 + 1;
486 result = pRtlUniform(&seed);
487 ok(result == expected,
488 "RtlUniform(&seed (seed == 1)) returns %x, expected %x\n",
489 result, expected);
490 /*
491 * For seed = 2 the const_2 is 0x7fffffc3:
492 */
493 seed = 2;
494 expected = seed * 0xffffffed + 0x7fffffc3;
495 result = pRtlUniform(&seed);
496
497 /*
498 * Windows Vista uses different algorithms, so skip the rest of the tests
499 * until that is figured out. Trace output for the failures is about 10.5 MB!
500 */
501
502 if (result == 0x7fffff9f) {
503 skip("Most likely running on Windows Vista which uses a different algorithm\n");
504 return;
505 }
506
507 ok(result == expected,
508 "RtlUniform(&seed (seed == 2)) returns %x, expected %x\n",
509 result, expected);
510
511 /*
512 * More tests show that if seed is odd the result must be incremented by 1:
513 */
514 seed = 3;
515 expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1);
516 result = pRtlUniform(&seed);
517 ok(result == expected,
518 "RtlUniform(&seed (seed == 3)) returns %x, expected %x\n",
519 result, expected);
520
521 seed = 0x6bca1aa;
522 expected = seed * 0xffffffed + 0x7fffffc3;
523 result = pRtlUniform(&seed);
524 ok(result == expected,
525 "RtlUniform(&seed (seed == 0x6bca1aa)) returns %x, expected %x\n",
526 result, expected);
527
528 seed = 0x6bca1ab;
529 expected = seed * 0xffffffed + 0x7fffffc3 + 1;
530 result = pRtlUniform(&seed);
531 ok(result == expected,
532 "RtlUniform(&seed (seed == 0x6bca1ab)) returns %x, expected %x\n",
533 result, expected);
534 /*
535 * When seed is 0x6bca1ac there is an exception:
536 */
537 seed = 0x6bca1ac;
538 expected = seed * 0xffffffed + 0x7fffffc3 + 2;
539 result = pRtlUniform(&seed);
540 ok(result == expected,
541 "RtlUniform(&seed (seed == 0x6bca1ac)) returns %x, expected %x\n",
542 result, expected);
543 /*
544 * Note that up to here const_3 is not used
545 * (the highest bit of the result is not set).
546 *
547 * Starting with 0x6bca1ad: If seed is even the result must be incremented by 1:
548 */
549 seed = 0x6bca1ad;
550 expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG;
551 result = pRtlUniform(&seed);
552 ok(result == expected,
553 "RtlUniform(&seed (seed == 0x6bca1ad)) returns %x, expected %x\n",
554 result, expected);
555
556 seed = 0x6bca1ae;
557 expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG;
558 result = pRtlUniform(&seed);
559 ok(result == expected,
560 "RtlUniform(&seed (seed == 0x6bca1ae)) returns %x, expected %x\n",
561 result, expected);
562 /*
563 * There are several ranges where for odd or even seed the result must be
564 * incremented by 1. You can see this ranges in the following test.
565 *
566 * For a full test use one of the following loop heads:
567 *
568 * for (num = 0; num <= 0xffffffff; num++) {
569 * seed = num;
570 * ...
571 *
572 * seed = 0;
573 * for (num = 0; num <= 0xffffffff; num++) {
574 * ...
575 */
576 seed = 0;
577 for (num = 0; num <= 100000; num++) {
578
579 expected = seed * 0xffffffed + 0x7fffffc3;
580 if (seed < 0x6bca1ac) {
581 expected = expected + (seed & 1);
582 } else if (seed == 0x6bca1ac) {
583 expected = (expected + 2) & MAXLONG;
584 } else if (seed < 0xd79435c) {
585 expected = (expected + (~seed & 1)) & MAXLONG;
586 } else if (seed < 0x1435e50b) {
587 expected = expected + (seed & 1);
588 } else if (seed < 0x1af286ba) {
589 expected = (expected + (~seed & 1)) & MAXLONG;
590 } else if (seed < 0x21af2869) {
591 expected = expected + (seed & 1);
592 } else if (seed < 0x286bca18) {
593 expected = (expected + (~seed & 1)) & MAXLONG;
594 } else if (seed < 0x2f286bc7) {
595 expected = expected + (seed & 1);
596 } else if (seed < 0x35e50d77) {
597 expected = (expected + (~seed & 1)) & MAXLONG;
598 } else if (seed < 0x3ca1af26) {
599 expected = expected + (seed & 1);
600 } else if (seed < 0x435e50d5) {
601 expected = (expected + (~seed & 1)) & MAXLONG;
602 } else if (seed < 0x4a1af284) {
603 expected = expected + (seed & 1);
604 } else if (seed < 0x50d79433) {
605 expected = (expected + (~seed & 1)) & MAXLONG;
606 } else if (seed < 0x579435e2) {
607 expected = expected + (seed & 1);
608 } else if (seed < 0x5e50d792) {
609 expected = (expected + (~seed & 1)) & MAXLONG;
610 } else if (seed < 0x650d7941) {
611 expected = expected + (seed & 1);
612 } else if (seed < 0x6bca1af0) {
613 expected = (expected + (~seed & 1)) & MAXLONG;
614 } else if (seed < 0x7286bc9f) {
615 expected = expected + (seed & 1);
616 } else if (seed < 0x79435e4e) {
617 expected = (expected + (~seed & 1)) & MAXLONG;
618 } else if (seed < 0x7ffffffd) {
619 expected = expected + (seed & 1);
620 } else if (seed < 0x86bca1ac) {
621 expected = (expected + (~seed & 1)) & MAXLONG;
622 } else if (seed == 0x86bca1ac) {
623 expected = (expected + 1) & MAXLONG;
624 } else if (seed < 0x8d79435c) {
625 expected = expected + (seed & 1);
626 } else if (seed < 0x9435e50b) {
627 expected = (expected + (~seed & 1)) & MAXLONG;
628 } else if (seed < 0x9af286ba) {
629 expected = expected + (seed & 1);
630 } else if (seed < 0xa1af2869) {
631 expected = (expected + (~seed & 1)) & MAXLONG;
632 } else if (seed < 0xa86bca18) {
633 expected = expected + (seed & 1);
634 } else if (seed < 0xaf286bc7) {
635 expected = (expected + (~seed & 1)) & MAXLONG;
636 } else if (seed == 0xaf286bc7) {
637 expected = (expected + 2) & MAXLONG;
638 } else if (seed < 0xb5e50d77) {
639 expected = expected + (seed & 1);
640 } else if (seed < 0xbca1af26) {
641 expected = (expected + (~seed & 1)) & MAXLONG;
642 } else if (seed < 0xc35e50d5) {
643 expected = expected + (seed & 1);
644 } else if (seed < 0xca1af284) {
645 expected = (expected + (~seed & 1)) & MAXLONG;
646 } else if (seed < 0xd0d79433) {
647 expected = expected + (seed & 1);
648 } else if (seed < 0xd79435e2) {
649 expected = (expected + (~seed & 1)) & MAXLONG;
650 } else if (seed < 0xde50d792) {
651 expected = expected + (seed & 1);
652 } else if (seed < 0xe50d7941) {
653 expected = (expected + (~seed & 1)) & MAXLONG;
654 } else if (seed < 0xebca1af0) {
655 expected = expected + (seed & 1);
656 } else if (seed < 0xf286bc9f) {
657 expected = (expected + (~seed & 1)) & MAXLONG;
658 } else if (seed < 0xf9435e4e) {
659 expected = expected + (seed & 1);
660 } else if (seed < 0xfffffffd) {
661 expected = (expected + (~seed & 1)) & MAXLONG;
662 } else {
663 expected = expected + (seed & 1);
664 } /* if */
665 seed_bak = seed;
666 result = pRtlUniform(&seed);
667 ok(result == expected,
668 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
669 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
670 ok(seed == expected,
671 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
672 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
673 } /* for */
674 /*
675 * Further investigation shows: In the different regions the highest bit
676 * is set or cleared when even or odd seeds need an increment by 1.
677 * This leads to a simplified algorithm:
678 *
679 * seed = seed * 0xffffffed + 0x7fffffc3;
680 * if (seed == 0xffffffff || seed == 0x7ffffffe) {
681 * seed = (seed + 2) & MAXLONG;
682 * } else if (seed == 0x7fffffff) {
683 * seed = 0;
684 * } else if ((seed & 0x80000000) == 0) {
685 * seed = seed + (~seed & 1);
686 * } else {
687 * seed = (seed + (seed & 1)) & MAXLONG;
688 * }
689 *
690 * This is also the algorithm used for RtlUniform of wine (see dlls/ntdll/rtl.c).
691 *
692 * Now comes the funny part:
693 * It took me one weekend, to find the complicated algorithm and one day more,
694 * to find the simplified algorithm. Several weeks later I found out: The value
695 * MAXLONG (=0x7fffffff) is never returned, neither with the native function
696 * nor with the simplified algorithm. In reality the native function and our
697 * function return a random number distributed over [0..MAXLONG-1]. Note
698 * that this is different from what native documentation states [0..MAXLONG].
699 * Expressed with D.H. Lehmer's 1948 algorithm it looks like:
700 *
701 * seed = (seed * const_1 + const_2) % MAXLONG;
702 *
703 * Further investigations show that the real algorithm is:
704 *
705 * seed = (seed * 0x7fffffed + 0x7fffffc3) % MAXLONG;
706 *
707 * This is checked with the test below:
708 */
709 seed = 0;
710 for (num = 0; num <= 100000; num++) {
711 expected = (seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff;
712 seed_bak = seed;
713 result = pRtlUniform(&seed);
714 ok(result == expected,
715 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
716 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
717 ok(seed == expected,
718 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
719 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
720 } /* for */
721 /*
722 * More tests show that RtlUniform does not return 0x7ffffffd for seed values
723 * in the range [0..MAXLONG-1]. Additionally 2 is returned twice. This shows
724 * that there is more than one cycle of generated randon numbers ...
725 */
726 }
727
728
729 static void test_RtlRandom(void)
730 {
731 int i, j;
732 ULONG seed;
733 ULONG res[512];
734
735 if (!pRtlRandom)
736 {
737 win_skip("RtlRandom is not available\n");
738 return;
739 }
740
741 seed = 0;
742 for (i = 0; i < sizeof(res) / sizeof(res[0]); i++)
743 {
744 res[i] = pRtlRandom(&seed);
745 ok(seed != res[i], "%i: seed is same as res %x\n", i, seed);
746 for (j = 0; j < i; j++)
747 ok(res[i] != res[j], "res[%i] (%x) is same as res[%i] (%x)\n", j, res[j], i, res[i]);
748 }
749 }
750
751
752 typedef struct {
753 ACCESS_MASK GrantedAccess;
754 ACCESS_MASK DesiredAccess;
755 BOOLEAN result;
756 } all_accesses_t;
757
758 static const all_accesses_t all_accesses[] = {
759 {0xFEDCBA76, 0xFEDCBA76, 1},
760 {0x00000000, 0xFEDCBA76, 0},
761 {0xFEDCBA76, 0x00000000, 1},
762 {0x00000000, 0x00000000, 1},
763 {0xFEDCBA76, 0xFEDCBA70, 1},
764 {0xFEDCBA70, 0xFEDCBA76, 0},
765 {0xFEDCBA76, 0xFEDC8A76, 1},
766 {0xFEDC8A76, 0xFEDCBA76, 0},
767 {0xFEDCBA76, 0xC8C4B242, 1},
768 {0xC8C4B242, 0xFEDCBA76, 0},
769 };
770 #define NB_ALL_ACCESSES (sizeof(all_accesses)/sizeof(*all_accesses))
771
772
773 static void test_RtlAreAllAccessesGranted(void)
774 {
775 unsigned int test_num;
776 BOOLEAN result;
777
778 if (!pRtlAreAllAccessesGranted)
779 {
780 win_skip("RtlAreAllAccessesGranted is not available\n");
781 return;
782 }
783
784 for (test_num = 0; test_num < NB_ALL_ACCESSES; test_num++) {
785 result = pRtlAreAllAccessesGranted(all_accesses[test_num].GrantedAccess,
786 all_accesses[test_num].DesiredAccess);
787 ok(all_accesses[test_num].result == result,
788 "(test %d): RtlAreAllAccessesGranted(%08x, %08x) returns %d, expected %d\n",
789 test_num, all_accesses[test_num].GrantedAccess,
790 all_accesses[test_num].DesiredAccess,
791 result, all_accesses[test_num].result);
792 } /* for */
793 }
794
795
796 typedef struct {
797 ACCESS_MASK GrantedAccess;
798 ACCESS_MASK DesiredAccess;
799 BOOLEAN result;
800 } any_accesses_t;
801
802 static const any_accesses_t any_accesses[] = {
803 {0xFEDCBA76, 0xFEDCBA76, 1},
804 {0x00000000, 0xFEDCBA76, 0},
805 {0xFEDCBA76, 0x00000000, 0},
806 {0x00000000, 0x00000000, 0},
807 {0xFEDCBA76, 0x01234589, 0},
808 {0x00040000, 0xFEDCBA76, 1},
809 {0x00040000, 0xFED8BA76, 0},
810 {0xFEDCBA76, 0x00040000, 1},
811 {0xFED8BA76, 0x00040000, 0},
812 };
813 #define NB_ANY_ACCESSES (sizeof(any_accesses)/sizeof(*any_accesses))
814
815
816 static void test_RtlAreAnyAccessesGranted(void)
817 {
818 unsigned int test_num;
819 BOOLEAN result;
820
821 if (!pRtlAreAnyAccessesGranted)
822 {
823 win_skip("RtlAreAnyAccessesGranted is not available\n");
824 return;
825 }
826
827 for (test_num = 0; test_num < NB_ANY_ACCESSES; test_num++) {
828 result = pRtlAreAnyAccessesGranted(any_accesses[test_num].GrantedAccess,
829 any_accesses[test_num].DesiredAccess);
830 ok(any_accesses[test_num].result == result,
831 "(test %d): RtlAreAnyAccessesGranted(%08x, %08x) returns %d, expected %d\n",
832 test_num, any_accesses[test_num].GrantedAccess,
833 any_accesses[test_num].DesiredAccess,
834 result, any_accesses[test_num].result);
835 } /* for */
836 }
837
838 static void test_RtlComputeCrc32(void)
839 {
840 DWORD crc = 0;
841
842 if (!pRtlComputeCrc32)
843 {
844 win_skip("RtlComputeCrc32 is not available\n");
845 return;
846 }
847
848 crc = pRtlComputeCrc32(crc, (const BYTE *)src, LEN);
849 ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8x\n", crc);
850 }
851
852
853 typedef struct MY_HANDLE
854 {
855 RTL_HANDLE RtlHandle;
856 void * MyValue;
857 } MY_HANDLE;
858
859 static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
860 {
861 ULONG_PTR *AllocatedBit = (ULONG_PTR *)(&Handle->Next);
862 *AllocatedBit = *AllocatedBit | 1;
863 }
864
865 static void test_HandleTables(void)
866 {
867 BOOLEAN result;
868 NTSTATUS status;
869 ULONG Index;
870 MY_HANDLE * MyHandle;
871 RTL_HANDLE_TABLE HandleTable;
872
873 if (!pRtlInitializeHandleTable)
874 {
875 win_skip("RtlInitializeHandleTable is not available\n");
876 return;
877 }
878
879 pRtlInitializeHandleTable(0x3FFF, sizeof(MY_HANDLE), &HandleTable);
880 MyHandle = (MY_HANDLE *)pRtlAllocateHandle(&HandleTable, &Index);
881 ok(MyHandle != NULL, "RtlAllocateHandle failed\n");
882 RtlpMakeHandleAllocated(&MyHandle->RtlHandle);
883 MyHandle = NULL;
884 result = pRtlIsValidIndexHandle(&HandleTable, Index, (RTL_HANDLE **)&MyHandle);
885 ok(result, "Handle %p wasn't valid\n", MyHandle);
886 result = pRtlFreeHandle(&HandleTable, &MyHandle->RtlHandle);
887 ok(result, "Couldn't free handle %p\n", MyHandle);
888 status = pRtlDestroyHandleTable(&HandleTable);
889 ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08x\n", status);
890 }
891
892 static void test_RtlAllocateAndInitializeSid(void)
893 {
894 NTSTATUS ret;
895 SID_IDENTIFIER_AUTHORITY sia = {{ 1, 2, 3, 4, 5, 6 }};
896 PSID psid;
897
898 if (!pRtlAllocateAndInitializeSid)
899 {
900 win_skip("RtlAllocateAndInitializeSid is not available\n");
901 return;
902 }
903
904 ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
905 ok(!ret, "RtlAllocateAndInitializeSid error %08x\n", ret);
906 ret = pRtlFreeSid(psid);
907 ok(!ret, "RtlFreeSid error %08x\n", ret);
908
909 /* these tests crash on XP */
910 if (0)
911 {
912 pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
913 pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL);
914 }
915
916 ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
917 ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret);
918 }
919
920 static void test_RtlDeleteTimer(void)
921 {
922 NTSTATUS ret;
923
924 if (!pRtlDeleteTimer)
925 {
926 win_skip("RtlDeleteTimer is not available\n");
927 return;
928 }
929
930 ret = pRtlDeleteTimer(NULL, NULL, NULL);
931 ok(ret == STATUS_INVALID_PARAMETER_1 ||
932 ret == STATUS_INVALID_PARAMETER, /* W2K */
933 "expected STATUS_INVALID_PARAMETER_1 or STATUS_INVALID_PARAMETER, got %x\n", ret);
934 }
935
936 static void test_RtlThreadErrorMode(void)
937 {
938 DWORD oldmode;
939 BOOL is_wow64;
940 DWORD mode;
941 NTSTATUS status;
942
943 if (!pRtlGetThreadErrorMode || !pRtlSetThreadErrorMode)
944 {
945 win_skip("RtlGetThreadErrorMode and/or RtlSetThreadErrorMode not available\n");
946 return;
947 }
948
949 if (!pIsWow64Process || !pIsWow64Process(GetCurrentProcess(), &is_wow64))
950 is_wow64 = FALSE;
951
952 oldmode = pRtlGetThreadErrorMode();
953
954 status = pRtlSetThreadErrorMode(0x70, &mode);
955 ok(status == STATUS_SUCCESS ||
956 status == STATUS_WAIT_1, /* Vista */
957 "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
958 ok(mode == oldmode,
959 "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
960 mode, oldmode);
961 ok(pRtlGetThreadErrorMode() == 0x70,
962 "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70);
963 if (!is_wow64 && pNtCurrentTeb)
964 ok(pNtCurrentTeb()->HardErrorDisabled == 0x70,
965 "The TEB contains 0x%x, expected 0x%x\n",
966 pNtCurrentTeb()->HardErrorDisabled, 0x70);
967
968 status = pRtlSetThreadErrorMode(0, &mode);
969 ok(status == STATUS_SUCCESS ||
970 status == STATUS_WAIT_1, /* Vista */
971 "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
972 ok(mode == 0x70,
973 "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
974 mode, 0x70);
975 ok(pRtlGetThreadErrorMode() == 0,
976 "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0);
977 if (!is_wow64 && pNtCurrentTeb)
978 ok(pNtCurrentTeb()->HardErrorDisabled == 0,
979 "The TEB contains 0x%x, expected 0x%x\n",
980 pNtCurrentTeb()->HardErrorDisabled, 0);
981
982 for (mode = 1; mode; mode <<= 1)
983 {
984 status = pRtlSetThreadErrorMode(mode, NULL);
985 if (mode & 0x70)
986 ok(status == STATUS_SUCCESS ||
987 status == STATUS_WAIT_1, /* Vista */
988 "RtlSetThreadErrorMode(%x,NULL) failed with error 0x%08x\n",
989 mode, status);
990 else
991 ok(status == STATUS_INVALID_PARAMETER_1,
992 "RtlSetThreadErrorMode(%x,NULL) returns 0x%08x, "
993 "expected STATUS_INVALID_PARAMETER_1\n",
994 mode, status);
995 }
996
997 pRtlSetThreadErrorMode(oldmode, NULL);
998 }
999
1000 static void test_LdrProcessRelocationBlock(void)
1001 {
1002 IMAGE_BASE_RELOCATION *ret;
1003 USHORT reloc;
1004 DWORD addr32;
1005 SHORT addr16;
1006
1007 if(!pLdrProcessRelocationBlock) {
1008 win_skip("LdrProcessRelocationBlock not available\n");
1009 return;
1010 }
1011
1012 addr32 = 0x50005;
1013 reloc = IMAGE_REL_BASED_HIGHLOW<<12;
1014 ret = pLdrProcessRelocationBlock(&addr32, 1, &reloc, 0x500050);
1015 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1016 ok(addr32 == 0x550055, "addr32 = %x, expected 0x550055\n", addr32);
1017
1018 addr16 = 0x505;
1019 reloc = IMAGE_REL_BASED_HIGH<<12;
1020 ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
1021 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1022 ok(addr16 == 0x555, "addr16 = %x, expected 0x555\n", addr16);
1023
1024 addr16 = 0x505;
1025 reloc = IMAGE_REL_BASED_LOW<<12;
1026 ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
1027 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1028 ok(addr16 == 0x565, "addr16 = %x, expected 0x565\n", addr16);
1029 }
1030
1031 static void test_RtlIpv4AddressToString(void)
1032 {
1033 CHAR buffer[20];
1034 CHAR *res;
1035 IN_ADDR ip;
1036 DWORD_PTR len;
1037
1038 if (!pRtlIpv4AddressToStringA)
1039 {
1040 win_skip("RtlIpv4AddressToStringA not available\n");
1041 return;
1042 }
1043
1044 ip.S_un.S_un_b.s_b1 = 1;
1045 ip.S_un.S_un_b.s_b2 = 2;
1046 ip.S_un.S_un_b.s_b3 = 3;
1047 ip.S_un.S_un_b.s_b4 = 4;
1048
1049 memset(buffer, '#', sizeof(buffer) - 1);
1050 buffer[sizeof(buffer) -1] = 0;
1051 res = pRtlIpv4AddressToStringA(&ip, buffer);
1052 len = strlen(buffer);
1053 ok(res == (buffer + len), "got %p with '%s' (expected %p)\n", res, buffer, buffer + len);
1054
1055 res = pRtlIpv4AddressToStringA(&ip, NULL);
1056 ok( (res == (char *)~0) ||
1057 broken(res == (char *)len), /* XP and w2003 */
1058 "got %p (expected ~0)\n", res);
1059
1060 if (0) {
1061 /* this crashes in windows */
1062 memset(buffer, '#', sizeof(buffer) - 1);
1063 buffer[sizeof(buffer) -1] = 0;
1064 res = pRtlIpv4AddressToStringA(NULL, buffer);
1065 trace("got %p with '%s'\n", res, buffer);
1066 }
1067
1068 if (0) {
1069 /* this crashes in windows */
1070 res = pRtlIpv4AddressToStringA(NULL, NULL);
1071 trace("got %p\n", res);
1072 }
1073 }
1074
1075 static void test_RtlIpv4AddressToStringEx(void)
1076 {
1077 CHAR ip_1234[] = "1.2.3.4";
1078 CHAR ip_1234_80[] = "1.2.3.4:80";
1079 LPSTR expect;
1080 CHAR buffer[30];
1081 NTSTATUS res;
1082 IN_ADDR ip;
1083 ULONG size;
1084 DWORD used;
1085 USHORT port;
1086
1087 if (!pRtlIpv4AddressToStringExA)
1088 {
1089 win_skip("RtlIpv4AddressToStringExA not available\n");
1090 return;
1091 }
1092
1093 ip.S_un.S_un_b.s_b1 = 1;
1094 ip.S_un.S_un_b.s_b2 = 2;
1095 ip.S_un.S_un_b.s_b3 = 3;
1096 ip.S_un.S_un_b.s_b4 = 4;
1097
1098 port = htons(80);
1099 expect = ip_1234_80;
1100
1101 size = sizeof(buffer);
1102 memset(buffer, '#', sizeof(buffer) - 1);
1103 buffer[sizeof(buffer) -1] = 0;
1104 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1105 used = strlen(buffer);
1106 ok( (res == STATUS_SUCCESS) &&
1107 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1108 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1109
1110 size = used + 1;
1111 memset(buffer, '#', sizeof(buffer) - 1);
1112 buffer[sizeof(buffer) -1] = 0;
1113 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1114 ok( (res == STATUS_SUCCESS) &&
1115 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1116 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1117
1118 size = used;
1119 memset(buffer, '#', sizeof(buffer) - 1);
1120 buffer[sizeof(buffer) -1] = 0;
1121 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1122 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1123 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1124 res, size, buffer, used + 1);
1125
1126 size = used - 1;
1127 memset(buffer, '#', sizeof(buffer) - 1);
1128 buffer[sizeof(buffer) -1] = 0;
1129 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1130 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1131 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1132 res, size, buffer, used + 1);
1133
1134
1135 /* to get only the ip, use 0 as port */
1136 port = 0;
1137 expect = ip_1234;
1138
1139 size = sizeof(buffer);
1140 memset(buffer, '#', sizeof(buffer) - 1);
1141 buffer[sizeof(buffer) -1] = 0;
1142 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1143 used = strlen(buffer);
1144 ok( (res == STATUS_SUCCESS) &&
1145 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1146 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1147
1148 size = used + 1;
1149 memset(buffer, '#', sizeof(buffer) - 1);
1150 buffer[sizeof(buffer) -1] = 0;
1151 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1152 ok( (res == STATUS_SUCCESS) &&
1153 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1154 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1155
1156 size = used;
1157 memset(buffer, '#', sizeof(buffer) - 1);
1158 buffer[sizeof(buffer) -1] = 0;
1159 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1160 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1161 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1162 res, size, buffer, used + 1);
1163
1164 size = used - 1;
1165 memset(buffer, '#', sizeof(buffer) - 1);
1166 buffer[sizeof(buffer) -1] = 0;
1167 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1168 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1169 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1170 res, size, buffer, used + 1);
1171
1172
1173 /* parameters are checked */
1174 memset(buffer, '#', sizeof(buffer) - 1);
1175 buffer[sizeof(buffer) -1] = 0;
1176 res = pRtlIpv4AddressToStringExA(&ip, 0, buffer, NULL);
1177 ok(res == STATUS_INVALID_PARAMETER,
1178 "got 0x%x with '%s' (expected STATUS_INVALID_PARAMETER)\n", res, buffer);
1179
1180 size = sizeof(buffer);
1181 res = pRtlIpv4AddressToStringExA(&ip, 0, NULL, &size);
1182 ok( res == STATUS_INVALID_PARAMETER,
1183 "got 0x%x and size %d (expected STATUS_INVALID_PARAMETER)\n", res, size);
1184
1185 size = sizeof(buffer);
1186 memset(buffer, '#', sizeof(buffer) - 1);
1187 buffer[sizeof(buffer) -1] = 0;
1188 res = pRtlIpv4AddressToStringExA(NULL, 0, buffer, &size);
1189 ok( res == STATUS_INVALID_PARAMETER,
1190 "got 0x%x and size %d with '%s' (expected STATUS_INVALID_PARAMETER)\n",
1191 res, size, buffer);
1192 }
1193
1194 static struct
1195 {
1196 PCSTR address;
1197 NTSTATUS res;
1198 int terminator_offset;
1199 int ip[4];
1200 enum { normal_4, strict_diff_4 = 1, ex_fail_4 = 2 } flags;
1201 NTSTATUS res_strict;
1202 int terminator_offset_strict;
1203 int ip_strict[4];
1204 } ipv4_tests[] =
1205 {
1206 { "", STATUS_INVALID_PARAMETER, 0, { -1 } },
1207 { " ", STATUS_INVALID_PARAMETER, 0, { -1 } },
1208 { "1.1.1.1", STATUS_SUCCESS, 7, { 1, 1, 1, 1 } },
1209 { "0.0.0.0", STATUS_SUCCESS, 7, { 0, 0, 0, 0 } },
1210 { "255.255.255.255", STATUS_SUCCESS, 15, { 255, 255, 255, 255 } },
1211 { "255.255.255.255:123", STATUS_SUCCESS, 15, { 255, 255, 255, 255 } },
1212 { "255.255.255.256", STATUS_INVALID_PARAMETER, 15, { -1 } },
1213 { "255.255.255.4294967295", STATUS_INVALID_PARAMETER, 22, { -1 } },
1214 { "255.255.255.4294967296", STATUS_INVALID_PARAMETER, 21, { -1 } },
1215 { "255.255.255.4294967297", STATUS_INVALID_PARAMETER, 21, { -1 } },
1216 { "a", STATUS_INVALID_PARAMETER, 0, { -1 } },
1217 { "1.1.1.0xaA", STATUS_SUCCESS, 10, { 1, 1, 1, 170 }, strict_diff_4,
1218 STATUS_INVALID_PARAMETER, 8, { -1 } },
1219 { "1.1.1.0XaA", STATUS_SUCCESS, 10, { 1, 1, 1, 170 }, strict_diff_4,
1220 STATUS_INVALID_PARAMETER, 8, { -1 } },
1221 { "1.1.1.0x", STATUS_INVALID_PARAMETER, 8, { -1 } },
1222 { "1.1.1.0xff", STATUS_SUCCESS, 10, { 1, 1, 1, 255 }, strict_diff_4,
1223 STATUS_INVALID_PARAMETER, 8, { -1 } },
1224 { "1.1.1.0x100", STATUS_INVALID_PARAMETER, 11, { -1 }, strict_diff_4,
1225 STATUS_INVALID_PARAMETER, 8, { -1 } },
1226 { "1.1.1.0xffffffff", STATUS_INVALID_PARAMETER, 16, { -1 }, strict_diff_4,
1227 STATUS_INVALID_PARAMETER, 8, { -1 } },
1228 { "1.1.1.0x100000000", STATUS_INVALID_PARAMETER, 16, { -1, 0, 0, 0 }, strict_diff_4,
1229 STATUS_INVALID_PARAMETER, 8, { -1 } },
1230 { "1.1.1.010", STATUS_SUCCESS, 9, { 1, 1, 1, 8 }, strict_diff_4,
1231 STATUS_INVALID_PARAMETER, 7, { -1 } },
1232 { "1.1.1.00", STATUS_SUCCESS, 8, { 1, 1, 1, 0 }, strict_diff_4,
1233 STATUS_INVALID_PARAMETER, 7, { -1 } },
1234 { "1.1.1.007", STATUS_SUCCESS, 9, { 1, 1, 1, 7 }, strict_diff_4,
1235 STATUS_INVALID_PARAMETER, 7, { -1 } },
1236 { "1.1.1.08", STATUS_INVALID_PARAMETER, 7, { -1 } },
1237 { "1.1.1.008", STATUS_SUCCESS, 8, { 1, 1, 1, 0 }, strict_diff_4 | ex_fail_4,
1238 STATUS_INVALID_PARAMETER, 7, { -1 } },
1239 { "1.1.1.0a", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1240 { "1.1.1.0o10", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1241 { "1.1.1.0b10", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1242 { "1.1.1.-2", STATUS_INVALID_PARAMETER, 6, { -1 } },
1243 { "1", STATUS_SUCCESS, 1, { 0, 0, 0, 1 }, strict_diff_4,
1244 STATUS_INVALID_PARAMETER, 1, { -1 } },
1245 { "-1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1246 { "203569230", STATUS_SUCCESS, 9, { 12, 34, 56, 78 }, strict_diff_4,
1247 STATUS_INVALID_PARAMETER, 9, { -1 } },
1248 { "1.223756", STATUS_SUCCESS, 8, { 1, 3, 106, 12 }, strict_diff_4,
1249 STATUS_INVALID_PARAMETER, 8, { -1 } },
1250 { "3.4.756", STATUS_SUCCESS, 7, { 3, 4, 2, 244 }, strict_diff_4,
1251 STATUS_INVALID_PARAMETER, 7, { -1 } },
1252 { "3.4.756.1", STATUS_INVALID_PARAMETER, 9, { -1 } },
1253 { "3.4.65536", STATUS_INVALID_PARAMETER, 9, { -1 } },
1254 { "3.4.5.6.7", STATUS_INVALID_PARAMETER, 7, { -1 } },
1255 { "3.4.5.+6", STATUS_INVALID_PARAMETER, 6, { -1 } },
1256 { " 3.4.5.6", STATUS_INVALID_PARAMETER, 0, { -1 } },
1257 { "\t3.4.5.6", STATUS_INVALID_PARAMETER, 0, { -1 } },
1258 { "3.4.5.6 ", STATUS_SUCCESS, 7, { 3, 4, 5, 6 }, ex_fail_4 },
1259 { "3. 4.5.6", STATUS_INVALID_PARAMETER, 2, { -1 } },
1260 { ".", STATUS_INVALID_PARAMETER, 1, { -1 } },
1261 { "..", STATUS_INVALID_PARAMETER, 1, { -1 } },
1262 { "1.", STATUS_INVALID_PARAMETER, 2, { -1 } },
1263 { "1..", STATUS_INVALID_PARAMETER, 3, { -1 } },
1264 { ".1", STATUS_INVALID_PARAMETER, 1, { -1 } },
1265 { ".1.", STATUS_INVALID_PARAMETER, 1, { -1 } },
1266 { ".1.2.3", STATUS_INVALID_PARAMETER, 1, { -1 } },
1267 { "0.1.2.3", STATUS_SUCCESS, 7, { 0, 1, 2, 3 } },
1268 { "0.1.2.3.", STATUS_INVALID_PARAMETER, 7, { -1 } },
1269 { "[0.1.2.3]", STATUS_INVALID_PARAMETER, 0, { -1 } },
1270 { "::1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1271 { ":1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1272 };
1273 const unsigned int ipv4_testcount = sizeof(ipv4_tests) / sizeof(ipv4_tests[0]);
1274
1275 static void init_ip4(IN_ADDR* addr, const int src[4])
1276 {
1277 if (!src || src[0] == -1)
1278 {
1279 addr->S_un.S_addr = 0xabababab;
1280 }
1281 else
1282 {
1283 addr->S_un.S_un_b.s_b1 = src[0];
1284 addr->S_un.S_un_b.s_b2 = src[1];
1285 addr->S_un.S_un_b.s_b3 = src[2];
1286 addr->S_un.S_un_b.s_b4 = src[3];
1287 }
1288 }
1289
1290 static void test_RtlIpv4StringToAddress(void)
1291 {
1292 NTSTATUS res;
1293 IN_ADDR ip, expected_ip;
1294 PCSTR terminator;
1295 CHAR dummy;
1296 unsigned int i;
1297
1298 if (!pRtlIpv4StringToAddressA)
1299 {
1300 skip("RtlIpv4StringToAddress not available\n");
1301 return;
1302 }
1303
1304 if (0)
1305 {
1306 /* leaving either parameter NULL crashes on Windows */
1307 res = pRtlIpv4StringToAddressA(NULL, FALSE, &terminator, &ip);
1308 res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, NULL, &ip);
1309 res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, &terminator, NULL);
1310 /* same for the wide char version */
1311 /*
1312 res = pRtlIpv4StringToAddressW(NULL, FALSE, &terminatorW, &ip);
1313 res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, NULL, &ip);
1314 res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, &terminatorW, NULL);
1315 */
1316 }
1317
1318 for (i = 0; i < ipv4_testcount; i++)
1319 {
1320 /* non-strict */
1321 terminator = &dummy;
1322 ip.S_un.S_addr = 0xabababab;
1323 res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, FALSE, &terminator, &ip);
1324 ok(res == ipv4_tests[i].res,
1325 "[%s] res = 0x%08x, expected 0x%08x\n",
1326 ipv4_tests[i].address, res, ipv4_tests[i].res);
1327 ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset,
1328 "[%s] terminator = %p, expected %p\n",
1329 ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset);
1330
1331 init_ip4(&expected_ip, ipv4_tests[i].ip);
1332 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1333 "[%s] ip = %08x, expected %08x\n",
1334 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1335
1336 if (!(ipv4_tests[i].flags & strict_diff_4))
1337 {
1338 ipv4_tests[i].res_strict = ipv4_tests[i].res;
1339 ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1340 ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1341 ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1342 ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1343 ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1344 }
1345 /* strict */
1346 terminator = &dummy;
1347 ip.S_un.S_addr = 0xabababab;
1348 res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, TRUE, &terminator, &ip);
1349 ok(res == ipv4_tests[i].res_strict,
1350 "[%s] res = 0x%08x, expected 0x%08x\n",
1351 ipv4_tests[i].address, res, ipv4_tests[i].res_strict);
1352 ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict,
1353 "[%s] terminator = %p, expected %p\n",
1354 ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict);
1355
1356 init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1357 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1358 "[%s] ip = %08x, expected %08x\n",
1359 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1360 }
1361 }
1362
1363 static void test_RtlIpv4StringToAddressEx(void)
1364 {
1365 NTSTATUS res;
1366 IN_ADDR ip, expected_ip;
1367 USHORT port;
1368 static const struct
1369 {
1370 PCSTR address;
1371 NTSTATUS res;
1372 int ip[4];
1373 USHORT port;
1374 } ipv4_ex_tests[] =
1375 {
1376 { "", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1377 { " ", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1378 { "1.1.1.1:", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
1379 { "1.1.1.1+", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
1380 { "1.1.1.1:1", STATUS_SUCCESS, { 1, 1, 1, 1 }, 0x100 },
1381 { "256.1.1.1:1", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1382 { "-1.1.1.1:1", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1383 { "0.0.0.0:0", STATUS_INVALID_PARAMETER, { 0, 0, 0, 0 }, 0xdead },
1384 { "0.0.0.0:1", STATUS_SUCCESS, { 0, 0, 0, 0 }, 0x100 },
1385 { "1.2.3.4:65535", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1386 { "1.2.3.4:65536", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1387 { "1.2.3.4:0xffff", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1388 { "1.2.3.4:0XfFfF", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1389 { "1.2.3.4:011064", STATUS_SUCCESS, { 1, 2, 3, 4 }, 0x3412 },
1390 { "1.2.3.4:1234a", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1391 { "1.2.3.4:1234+", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1392 { "1.2.3.4: 1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1393 { "1.2.3.4:\t1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1394 };
1395 const unsigned int ipv4_ex_testcount = sizeof(ipv4_ex_tests) / sizeof(ipv4_ex_tests[0]);
1396 unsigned int i;
1397 BOOLEAN strict;
1398
1399 if (!pRtlIpv4StringToAddressExA)
1400 {
1401 skip("RtlIpv4StringToAddressEx not available\n");
1402 return;
1403 }
1404
1405 /* do not crash, and do not touch the ip / port. */
1406 ip.S_un.S_addr = 0xabababab;
1407 port = 0xdead;
1408 res = pRtlIpv4StringToAddressExA(NULL, FALSE, &ip, &port);
1409 ok(res == STATUS_INVALID_PARAMETER, "[null address] res = 0x%08x, expected 0x%08x\n",
1410 res, STATUS_INVALID_PARAMETER);
1411 ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1412 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1413
1414 port = 0xdead;
1415 res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, NULL, &port);
1416 ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected 0x%08x\n",
1417 res, STATUS_INVALID_PARAMETER);
1418 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1419
1420 ip.S_un.S_addr = 0xabababab;
1421 port = 0xdead;
1422 res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, &ip, NULL);
1423 ok(res == STATUS_INVALID_PARAMETER, "[null port] res = 0x%08x, expected 0x%08x\n",
1424 res, STATUS_INVALID_PARAMETER);
1425 ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1426 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1427
1428 /* first we run the non-ex testcases on the ex function */
1429 for (i = 0; i < ipv4_testcount; i++)
1430 {
1431 NTSTATUS expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res;
1432
1433 /* non-strict */
1434 port = 0xdead;
1435 ip.S_un.S_addr = 0xabababab;
1436 res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, FALSE, &ip, &port);
1437 ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1438 ipv4_tests[i].address, res, expect_res);
1439
1440 init_ip4(&expected_ip, ipv4_tests[i].ip);
1441 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1442 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1443
1444 if (!(ipv4_tests[i].flags & strict_diff_4))
1445 {
1446 ipv4_tests[i].res_strict = ipv4_tests[i].res;
1447 ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1448 ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1449 ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1450 ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1451 ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1452 }
1453 /* strict */
1454 expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res_strict;
1455 port = 0xdead;
1456 ip.S_un.S_addr = 0xabababab;
1457 res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, TRUE, &ip, &port);
1458 ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1459 ipv4_tests[i].address, res, expect_res);
1460
1461 init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1462 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1463 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1464 }
1465
1466
1467 for (i = 0; i < ipv4_ex_testcount; i++)
1468 {
1469 /* Strict is only relevant for the ip address, so make sure that it does not influence the port */
1470 for (strict = 0; strict < 2; strict++)
1471 {
1472 ip.S_un.S_addr = 0xabababab;
1473 port = 0xdead;
1474 res = pRtlIpv4StringToAddressExA(ipv4_ex_tests[i].address, strict, &ip, &port);
1475 ok(res == ipv4_ex_tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
1476 ipv4_ex_tests[i].address, res, ipv4_ex_tests[i].res);
1477
1478 init_ip4(&expected_ip, ipv4_ex_tests[i].ip);
1479 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1480 ipv4_ex_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1481 ok(port == ipv4_ex_tests[i].port, "[%s] port = %u, expected %u\n",
1482 ipv4_ex_tests[i].address, port, ipv4_ex_tests[i].port);
1483 }
1484 }
1485 }
1486
1487 /* ipv6 addresses based on the set from https://github.com/beaugunderson/javascript-ipv6/tree/master/test/data */
1488 static const struct
1489 {
1490 PCSTR address;
1491 NTSTATUS res;
1492 int terminator_offset;
1493 int ip[8];
1494 /* win_broken: older versions of windows do not handle this correct
1495 ex_fail: Ex function does need the string to be terminated, non-Ex does not.
1496 ex_skip: test doesnt make sense for Ex (f.e. it's invalid for non-Ex but valid for Ex) */
1497 enum { normal_6, win_broken_6 = 1, ex_fail_6 = 2, ex_skip_6 = 4 } flags;
1498 } ipv6_tests[] =
1499 {
1500 { "0000:0000:0000:0000:0000:0000:0000:0000", STATUS_SUCCESS, 39,
1501 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1502 { "0000:0000:0000:0000:0000:0000:0000:0001", STATUS_SUCCESS, 39,
1503 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1504 { "0:0:0:0:0:0:0:0", STATUS_SUCCESS, 15,
1505 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1506 { "0:0:0:0:0:0:0:1", STATUS_SUCCESS, 15,
1507 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1508 { "0:0:0:0:0:0:0::", STATUS_SUCCESS, 13,
1509 { 0, 0, 0, 0, 0, 0, 0, 0 }, win_broken_6 },
1510 { "0:0:0:0:0:0:13.1.68.3", STATUS_SUCCESS, 21,
1511 { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1512 { "0:0:0:0:0:0::", STATUS_SUCCESS, 13,
1513 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1514 { "0:0:0:0:0::", STATUS_SUCCESS, 11,
1515 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1516 { "0:0:0:0:0:FFFF:129.144.52.38", STATUS_SUCCESS, 28,
1517 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
1518 { "0::", STATUS_SUCCESS, 3,
1519 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1520 { "0:1:2:3:4:5:6:7", STATUS_SUCCESS, 15,
1521 { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
1522 { "1080:0:0:0:8:800:200c:417a", STATUS_SUCCESS, 26,
1523 { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
1524 { "0:a:b:c:d:e:f::", STATUS_SUCCESS, 13,
1525 { 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0 }, win_broken_6 },
1526 { "1111:2222:3333:4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 45,
1527 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1528 { "1111:2222:3333:4444:5555:6666:7777:8888", STATUS_SUCCESS, 39,
1529 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1530 { "1111:2222:3333:4444:0x5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 21,
1531 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1532 { "1111:2222:3333:4444:x555:6666:7777:8888", STATUS_INVALID_PARAMETER, 20,
1533 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1534 { "1111:2222:3333:4444:0r5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 21,
1535 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1536 { "1111:2222:3333:4444:r5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 20,
1537 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1538 { "1111:2222:3333:4444:5555:6666:7777::", STATUS_SUCCESS, 34,
1539 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0 }, win_broken_6 },
1540 { "1111:2222:3333:4444:5555:6666::", STATUS_SUCCESS, 31,
1541 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
1542 { "1111:2222:3333:4444:5555:6666::8888", STATUS_SUCCESS, 35,
1543 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
1544 { "1111:2222:3333:4444:5555::", STATUS_SUCCESS, 26,
1545 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
1546 { "1111:2222:3333:4444:5555::123.123.123.123", STATUS_SUCCESS, 41,
1547 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
1548 { "1111:2222:3333:4444:5555::0x1.123.123.123", STATUS_SUCCESS, 27,
1549 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x100 }, ex_fail_6 },
1550 { "1111:2222:3333:4444:5555::0x88", STATUS_SUCCESS, 27,
1551 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1552 { "1111:2222:3333:4444:5555::0X88", STATUS_SUCCESS, 27,
1553 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1554 { "1111:2222:3333:4444:5555::0X", STATUS_SUCCESS, 27,
1555 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 }, ex_fail_6 },
1556 { "1111:2222:3333:4444:5555::0X88:7777", STATUS_SUCCESS, 27,
1557 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1558 { "1111:2222:3333:4444:5555::0x8888", STATUS_SUCCESS, 27,
1559 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 }, ex_fail_6 },
1560 { "1111:2222:3333:4444:5555::08888", STATUS_INVALID_PARAMETER, 31,
1561 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1562 { "1111:2222:3333:4444:5555::fffff", STATUS_INVALID_PARAMETER, 31,
1563 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1564 { "1111:2222:3333:4444::fffff", STATUS_INVALID_PARAMETER, 26,
1565 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1566 { "1111:2222:3333::fffff", STATUS_INVALID_PARAMETER, 21,
1567 { 0x1111, 0x2222, 0x3333, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1568 { "1111:2222:3333:4444:5555::7777:8888", STATUS_SUCCESS, 35,
1569 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
1570 { "1111:2222:3333:4444:5555::8888", STATUS_SUCCESS, 30,
1571 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
1572 { "1111::", STATUS_SUCCESS, 6,
1573 { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1574 { "1111::123.123.123.123", STATUS_SUCCESS, 21,
1575 { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1576 { "1111::3333:4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 41,
1577 { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1578 { "1111::3333:4444:5555:6666:7777:8888", STATUS_SUCCESS, 35,
1579 { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1580 { "1111::4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 36,
1581 { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1582 { "1111::4444:5555:6666:7777:8888", STATUS_SUCCESS, 30,
1583 { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1584 { "1111::5555:6666:123.123.123.123", STATUS_SUCCESS, 31,
1585 { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1586 { "1111::5555:6666:7777:8888", STATUS_SUCCESS, 25,
1587 { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
1588 { "1111::6666:123.123.123.123", STATUS_SUCCESS, 26,
1589 { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
1590 { "1111::6666:7777:8888", STATUS_SUCCESS, 20,
1591 { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
1592 { "1111::7777:8888", STATUS_SUCCESS, 15,
1593 { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
1594 { "1111::8888", STATUS_SUCCESS, 10,
1595 { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
1596 { "1:2:3:4:5:6:1.2.3.4", STATUS_SUCCESS, 19,
1597 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
1598 { "1:2:3:4:5:6:7:8", STATUS_SUCCESS, 15,
1599 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
1600 { "1:2:3:4:5:6::", STATUS_SUCCESS, 13,
1601 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
1602 { "1:2:3:4:5:6::8", STATUS_SUCCESS, 14,
1603 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
1604 { "2001:0000:1234:0000:0000:C1C0:ABCD:0876", STATUS_SUCCESS, 39,
1605 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1606 { "2001:0000:4136:e378:8000:63bf:3fff:fdd2", STATUS_SUCCESS, 39,
1607 { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
1608 { "2001:0db8:0:0:0:0:1428:57ab", STATUS_SUCCESS, 27,
1609 { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
1610 { "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff", STATUS_SUCCESS, 39,
1611 { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1612 { "2001::CE49:7601:2CAD:DFFF:7C94:FFFE", STATUS_SUCCESS, 35,
1613 { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
1614 { "2001:db8:85a3::8a2e:370:7334", STATUS_SUCCESS, 28,
1615 { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
1616 { "3ffe:0b00:0000:0000:0001:0000:0000:000a", STATUS_SUCCESS, 39,
1617 { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
1618 { "::", STATUS_SUCCESS, 2,
1619 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1620 { "::%16", STATUS_SUCCESS, 2,
1621 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1622 { "::/16", STATUS_SUCCESS, 2,
1623 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1624 { "::0", STATUS_SUCCESS, 3,
1625 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1626 { "::0:0", STATUS_SUCCESS, 5,
1627 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1628 { "::0:0:0", STATUS_SUCCESS, 7,
1629 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1630 { "::0:0:0:0", STATUS_SUCCESS, 9,
1631 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1632 { "::0:0:0:0:0", STATUS_SUCCESS, 11,
1633 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1634 { "::0:0:0:0:0:0", STATUS_SUCCESS, 13,
1635 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1636 /* this one and the next one are incorrectly parsed by windows,
1637 it adds one zero too many in front, cutting off the last digit. */
1638 { "::0:0:0:0:0:0:0", STATUS_SUCCESS, 13,
1639 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1640 { "::0:a:b:c:d:e:f", STATUS_SUCCESS, 13,
1641 { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 }, ex_fail_6 },
1642 { "::123.123.123.123", STATUS_SUCCESS, 17,
1643 { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1644 { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", STATUS_SUCCESS, 39,
1645 { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1646
1647 { "':10.0.0.1", STATUS_INVALID_PARAMETER, 0,
1648 { -1 } },
1649 { "-1", STATUS_INVALID_PARAMETER, 0,
1650 { -1 } },
1651 { "02001:0000:1234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1652 { -1 } },
1653 { "2001:00000:1234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1654 { 0x120, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1655 { "2001:0000:01234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1656 { 0x120, 0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1657 { "1.2.3.4", STATUS_INVALID_PARAMETER, 7,
1658 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1659 { "1.2.3.4:1111::5555", STATUS_INVALID_PARAMETER, 7,
1660 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1661 { "1.2.3.4::5555", STATUS_INVALID_PARAMETER, 7,
1662 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1663 { "11112222:3333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, -1,
1664 { -1 } },
1665 { "11112222:3333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, -1,
1666 { -1 } },
1667 { "1111", STATUS_INVALID_PARAMETER, 4,
1668 { -1 } },
1669 { "1111:22223333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, -1,
1670 { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1671 { "1111:22223333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, -1,
1672 { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1673 { "1111:2222:", STATUS_INVALID_PARAMETER, 10,
1674 { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1675 { "1111:2222:1.2.3.4", STATUS_INVALID_PARAMETER, 17,
1676 { 0x1111, 0x2222, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab } },
1677 { "1111:2222:3333", STATUS_INVALID_PARAMETER, 14,
1678 { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1679 { "1111:2222:3333:4444:5555:6666:7777:1.2.3.4", STATUS_SUCCESS, 36,
1680 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 }, ex_fail_6 },
1681 { "1111:2222:3333:4444:5555:6666:7777:8888:", STATUS_SUCCESS, 39,
1682 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1683 { "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",STATUS_SUCCESS, 39,
1684 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1685 { "1111:2222:3333:4444:5555:6666:7777:8888:9999", STATUS_SUCCESS, 39,
1686 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1687 { "1111:2222:::", STATUS_SUCCESS, 11,
1688 { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1689 { "1111::5555:", STATUS_INVALID_PARAMETER, 11,
1690 { 0x1111, 0x5555, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1691 { "1111::3333:4444:5555:6666:7777::", STATUS_SUCCESS, 30,
1692 { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 }, ex_fail_6 },
1693 { "1111:2222:::4444:5555:6666:1.2.3.4", STATUS_SUCCESS, 11,
1694 { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1695 { "1111::3333::5555:6666:1.2.3.4", STATUS_SUCCESS, 10,
1696 { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 }, ex_fail_6 },
1697 { "12345::6:7:8", STATUS_INVALID_PARAMETER, -1,
1698 { -1 } },
1699 { "1::1.2.256.4", STATUS_INVALID_PARAMETER, -1,
1700 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1701 { "1::1.2.3.256", STATUS_INVALID_PARAMETER, 12,
1702 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1703 { "1::1.2.3.300", STATUS_INVALID_PARAMETER, 12,
1704 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1705 { "1::1.2::1", STATUS_INVALID_PARAMETER, 6,
1706 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1707 { "1::1.2.3.4::1", STATUS_SUCCESS, 10,
1708 { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 }, ex_fail_6 },
1709 { "1::1.", STATUS_INVALID_PARAMETER, 5,
1710 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1711 { "1::1.2", STATUS_INVALID_PARAMETER, 6,
1712 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1713 { "1::1.2.", STATUS_INVALID_PARAMETER, 7,
1714 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1715 { "1::1.2.3", STATUS_INVALID_PARAMETER, 8,
1716 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1717 { "1::1.2.3.", STATUS_INVALID_PARAMETER, 9,
1718 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1719 { "1::1.2.3.4", STATUS_SUCCESS, 10,
1720 { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 } },
1721 { "1::1.2.3.900", STATUS_INVALID_PARAMETER, 12,
1722 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1723 { "1::1.2.300.4", STATUS_INVALID_PARAMETER, -1,
1724 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1725 { "1::1.256.3.4", STATUS_INVALID_PARAMETER, -1,
1726 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1727 { "1::256.2.3.4", STATUS_INVALID_PARAMETER, -1,
1728 { 0x100, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1729 { "1::2::3", STATUS_SUCCESS, 4,
1730 { 0x100, 0, 0, 0, 0, 0, 0, 0x200 }, ex_fail_6 },
1731 { "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, 15,
1732 { 0x120, 0, 0x3412, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1733 { "2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", STATUS_SUCCESS, 39,
1734 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 }, ex_fail_6 },
1735 { "2001:1:1:1:1:1:255Z255X255Y255", STATUS_INVALID_PARAMETER, 18,
1736 { 0x120, 0x100, 0x100, 0x100, 0x100, 0x100, 0xabab, 0xabab } },
1737 { "2001::FFD3::57ab", STATUS_SUCCESS, 10,
1738 { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff }, ex_fail_6 },
1739 { ":", STATUS_INVALID_PARAMETER, 0,
1740 { -1 } },
1741 { ":1111:2222:3333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, 0,
1742 { -1 } },
1743 { ":1111:2222:3333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 0,
1744 { -1 } },
1745 { ":1111::", STATUS_INVALID_PARAMETER, 0,
1746 { -1 } },
1747 { "::-1", STATUS_SUCCESS, 2,
1748 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1749 { "::.", STATUS_SUCCESS, 2,
1750 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1751 { "::..", STATUS_SUCCESS, 2,
1752 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1753 { "::...", STATUS_SUCCESS, 2,
1754 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1755 { "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4", STATUS_INVALID_PARAMETER, 0,
1756 { -1 } },
1757 { "[::]", STATUS_INVALID_PARAMETER, 0,
1758 { -1 }, ex_skip_6 },
1759 };
1760 const unsigned int ipv6_testcount = sizeof(ipv6_tests) / sizeof(ipv6_tests[0]);
1761
1762 static void init_ip6(IN6_ADDR* addr, const int src[8])
1763 {
1764 unsigned int j;
1765 if (!src || src[0] == -1)
1766 {
1767 for (j = 0; j < 8; ++j)
1768 addr->s6_words[j] = 0xabab;
1769 }
1770 else
1771 {
1772 for (j = 0; j < 8; ++j)
1773 addr->s6_words[j] = src[j];
1774 }
1775 }
1776
1777 static void test_RtlIpv6AddressToString(void)
1778 {
1779 CHAR buffer[50];
1780 LPCSTR result;
1781 IN6_ADDR ip;
1782 DWORD_PTR len;
1783 struct
1784 {
1785 PCSTR address;
1786 int ip[8];
1787 } tests[] =
1788 {
1789 /* ipv4 addresses & ISATAP addresses */
1790 { "::13.1.68.3", { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1791 { "::ffff:13.1.68.3", { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0x344 } },
1792 { "::feff:d01:4403", { 0, 0, 0, 0, 0, 0xfffe, 0x10d, 0x344 } },
1793 { "::fffe:d01:4403", { 0, 0, 0, 0, 0, 0xfeff, 0x10d, 0x344 } },
1794 { "::100:d01:4403", { 0, 0, 0, 0, 0, 1, 0x10d, 0x344 } },
1795 { "::1:d01:4403", { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1796 { "::ffff:0:4403", { 0, 0, 0, 0, 0, 0xffff, 0, 0x344 } },
1797 { "::ffff:13.1.0.0", { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0 } },
1798 { "::ffff:0:0", { 0, 0, 0, 0, 0, 0xffff, 0, 0 } },
1799 { "::ffff:0:13.1.68.3", { 0, 0, 0, 0, 0xffff, 0, 0x10d, 0x344 } },
1800 { "::ffff:ffff:d01:4403", { 0, 0, 0, 0, 0xffff, 0xffff, 0x10d, 0x344 } },
1801 { "::ffff:0:0:d01:4403", { 0, 0, 0, 0xffff, 0, 0, 0x10d, 0x344 } },
1802 { "::ffff:255.255.255.255", { 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff } },
1803 { "::ffff:129.144.52.38", { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
1804 { "::5efe:129.144.52.38", { 0, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1805 { "1111:2222:3333:4444:0:5efe:129.144.52.38", { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1806 { "1111:2222:3333::5efe:129.144.52.38", { 0x1111, 0x2222, 0x3333, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1807 { "1111:2222::5efe:129.144.52.38", { 0x1111, 0x2222, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1808 { "1111::5efe:129.144.52.38", { 0x1111, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1809 { "::200:5efe:129.144.52.38", { 0, 0, 0, 0, 2, 0xfe5e, 0x9081, 0x2634 } },
1810 { "::100:5efe:8190:3426", { 0, 0, 0, 0, 1, 0xfe5e, 0x9081, 0x2634 } },
1811 /* 'normal' addresses */
1812 { "::1", { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1813 { "0:1:2:3:4:5:6:7", { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
1814 { "1080::8:800:200c:417a", { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
1815 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1816 { "1111:2222:3333:4444:5555:6666:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1817 { "1111:2222:3333:4444:5555:6666::", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
1818 { "1111:2222:3333:4444:5555:6666:0:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
1819 { "1111:2222:3333:4444:5555::", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
1820 { "1111:2222:3333:4444:5555:0:7b7b:7b7b", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
1821 { "1111:2222:3333:4444:5555:0:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
1822 { "1111:2222:3333:4444:5555::8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
1823 { "1111::", { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1824 { "1111::7b7b:7b7b", { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1825 { "1111:0:3333:4444:5555:6666:7b7b:7b7b", { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1826 { "1111:0:3333:4444:5555:6666:7777:8888", { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1827 { "1111::4444:5555:6666:7b7b:7b7b", { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1828 { "1111::4444:5555:6666:7777:8888", { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1829 { "1111::5555:6666:7b7b:7b7b", { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1830 { "1111::5555:6666:7777:8888", { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
1831 { "1111::6666:7b7b:7b7b", { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
1832 { "1111::6666:7777:8888", { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
1833 { "1111::7777:8888", { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
1834 { "1111::8888", { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
1835 { "1:2:3:4:5:6:102:304", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
1836 { "1:2:3:4:5:6:7:8", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
1837 { "1:2:3:4:5:6::", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
1838 { "1:2:3:4:5:6:0:8", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
1839 { "2001:0:1234::c1c0:abcd:876", { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1840 { "2001:0:4136:e378:8000:63bf:3fff:fdd2", { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
1841 { "2001:db8::1428:57ab", { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
1842 { "2001:db8:1234:ffff:ffff:ffff:ffff:ffff", { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1843 { "2001:0:ce49:7601:2cad:dfff:7c94:fffe", { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
1844 { "2001:db8:85a3::8a2e:370:7334", { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
1845 { "3ffe:b00::1:0:0:a", { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
1846 { "::a:b:c:d:e", { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 } },
1847 { "::123.123.123.123", { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1848 { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1849 { "1111:2222:3333:4444:5555:6666:7777:1", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 } },
1850 { "1111:2222:3333:4444:5555:6666:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1851 { "1111:2222::", { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
1852 { "1111::3333:4444:5555:6666:7777", { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 } },
1853 { "1111:2222::", { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
1854 { "1111::3333", { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 } },
1855 { "2001:0:1234::c1c0:abcd:876", { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1856 { "2001::ffd3", { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1857 };
1858 const size_t testcount = sizeof(tests) / sizeof(tests[0]);
1859 unsigned int i;
1860
1861 if (!pRtlIpv6AddressToStringA)
1862 {
1863 skip("RtlIpv6AddressToStringA not available\n");
1864 return;
1865 }
1866
1867 memset(buffer, '#', sizeof(buffer));
1868 buffer[sizeof(buffer)-1] = 0;
1869 memset(&ip, 0, sizeof(ip));
1870 result = pRtlIpv6AddressToStringA(&ip, buffer);
1871
1872 len = strlen(buffer);
1873 ok(result == (buffer + len) && !strcmp(buffer, "::"),
1874 "got %p with '%s' (expected %p with '::')\n", result, buffer, buffer + len);
1875
1876 result = pRtlIpv6AddressToStringA(&ip, NULL);
1877 ok(result == (LPCSTR)~0 || broken(result == (LPCSTR)len) /* WinXP / Win2k3 */,
1878 "got %p, expected %p\n", result, (LPCSTR)~0);
1879
1880 for (i = 0; i < testcount; i++)
1881 {
1882 init_ip6(&ip, tests[i].ip);
1883 memset(buffer, '#', sizeof(buffer));
1884 buffer[sizeof(buffer)-1] = 0;
1885
1886 result = pRtlIpv6AddressToStringA(&ip, buffer);
1887 len = strlen(buffer);
1888 ok(result == (buffer + len) && !strcmp(buffer, tests[i].address),
1889 "got %p with '%s' (expected %p with '%s')\n", result, buffer, buffer + len, tests[i].address);
1890
1891 ok(buffer[45] == 0 || broken(buffer[45] != 0) /* WinXP / Win2k3 */,
1892 "expected data at buffer[45] to always be NULL\n");
1893 ok(buffer[46] == '#', "expected data at buffer[46] not to change\n");
1894 }
1895 }
1896
1897 static void test_RtlIpv6AddressToStringEx(void)
1898 {
1899 CHAR buffer[70];
1900 NTSTATUS res;
1901 IN6_ADDR ip;
1902 ULONG len;
1903 struct
1904 {
1905 PCSTR address;
1906 ULONG scopeid;
1907 USHORT port;
1908 int ip[8];
1909 } tests[] =
1910 {
1911 /* ipv4 addresses & ISATAP addresses */
1912 { "::13.1.68.3", 0, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1913 { "::13.1.68.3%1", 1, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1914 { "::13.1.68.3%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1915 { "[::13.1.68.3%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1916 { "[::13.1.68.3%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1917 { "[::13.1.68.3]:256", 0, 1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1918
1919 { "::1:d01:4403", 0, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1920 { "::1:d01:4403%1", 1, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1921 { "::1:d01:4403%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1922 { "[::1:d01:4403%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1923 { "[::1:d01:4403%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1924 { "[::1:d01:4403]:256", 0, 1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1925
1926 { "1111:2222:3333:4444:0:5efe:129.144.52.38", 0, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1927 { "1111:2222:3333:4444:0:5efe:129.144.52.38%1", 1, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1928 { "1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819", 0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1929 { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:65518",0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1930 { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1931 { "[1111:2222:3333:4444:0:5efe:129.144.52.38]:256", 0, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1932
1933 { "::1", 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1934 { "::1%1", 1, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1935 { "::1%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1936 { "[::1%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1937 { "[::1%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1938 { "[::1]:256", 0, 1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1939
1940 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b", 0, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1941 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%1", 1, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1942 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819", 0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1943 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1944 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1945 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b]:256", 0, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1946
1947 { "1111::", 0, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1948 { "1111::%1", 1, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1949 { "1111::%4294949819", 0xffffbbbb, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1950 { "[1111::%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1951 { "[1111::%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1952 { "[1111::]:256", 0, 1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1953
1954 { "2001::ffd3", 0, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1955 { "2001::ffd3%1", 1, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1956 { "2001::ffd3%4294949819", 0xffffbbbb, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1957 { "[2001::ffd3%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1958 { "[2001::ffd3%4294949819]:256", 0xffffbbbb, 1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1959 { "[2001::ffd3]:256", 0, 1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1960 };
1961 const size_t testcount = sizeof(tests) / sizeof(tests[0]);
1962 unsigned int i;
1963
1964 if (!pRtlIpv6AddressToStringExA)
1965 {
1966 skip("RtlIpv6AddressToStringExA not available\n");
1967 return;
1968 }
1969
1970 memset(buffer, '#', sizeof(buffer));
1971 buffer[sizeof(buffer)-1] = 0;
1972 memset(&ip, 0, sizeof(ip));
1973 len = sizeof(buffer);
1974 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
1975
1976 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
1977 ok(len == 3 && !strcmp(buffer, "::"),
1978 "got len %d with '%s' (expected 3 with '::')\n", len, buffer);
1979
1980 memset(buffer, '#', sizeof(buffer));
1981 buffer[sizeof(buffer)-1] = 0;
1982
1983 len = sizeof(buffer);
1984 res = pRtlIpv6AddressToStringExA(NULL, 0, 0, buffer, &len);
1985 ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1986
1987 len = sizeof(buffer);
1988 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, NULL, &len);
1989 ok(res == STATUS_INVALID_PARAMETER, "[null buffer] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1990
1991 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, NULL);
1992 ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1993
1994 len = 2;
1995 memset(buffer, '#', sizeof(buffer));
1996 buffer[sizeof(buffer)-1] = 0;
1997 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
1998 ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1999 ok(buffer[0] == '#', "got first char %c (expected '#')\n", buffer[0]);
2000 ok(len == 3, "got len %d (expected len 3)\n", len);
2001
2002 for (i = 0; i < testcount; i++)
2003 {
2004 init_ip6(&ip, tests[i].ip);
2005 len = sizeof(buffer);
2006 memset(buffer, '#', sizeof(buffer));
2007 buffer[sizeof(buffer)-1] = 0;
2008
2009 res = pRtlIpv6AddressToStringExA(&ip, tests[i].scopeid, tests[i].port, buffer, &len);
2010
2011 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2012 ok(len == (strlen(tests[i].address) + 1) && !strcmp(buffer, tests[i].address),
2013 "got len %d with '%s' (expected %d with '%s')\n", len, buffer, strlen(tests[i].address), tests[i].address);
2014 }
2015 }
2016
2017 static void compare_RtlIpv6StringToAddressW(PCSTR name_a, int terminator_offset_a,
2018 const struct in6_addr *addr_a, NTSTATUS res_a)
2019 {
2020 WCHAR name[512];
2021 NTSTATUS res;
2022 IN6_ADDR ip;
2023 PCWSTR terminator;
2024
2025 if (!pRtlIpv6StringToAddressW)
2026 return;
2027
2028 pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
2029
2030 init_ip6(&ip, NULL);
2031 terminator = (void *)0xdeadbeef;
2032 res = pRtlIpv6StringToAddressW(name, &terminator, &ip);
2033 ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2034
2035 if (terminator_offset_a < 0)
2036 {
2037 ok(terminator == (void *)0xdeadbeef,
2038 "[W:%s] terminator = %p, expected it not to change\n",
2039 name_a, terminator);
2040 }
2041 else
2042 {
2043 ok(terminator == name + terminator_offset_a,
2044 "[W:%s] terminator = %p, expected %p\n",
2045 name_a, terminator, name + terminator_offset_a);
2046 }
2047
2048 ok(!memcmp(&ip, addr_a, sizeof(ip)),
2049 "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2050 name_a,
2051 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2052 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2053 addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2054 addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2055 }
2056
2057 static void test_RtlIpv6StringToAddress(void)
2058 {
2059 NTSTATUS res;
2060 IN6_ADDR ip, expected_ip;
2061 PCSTR terminator;
2062 unsigned int i;
2063
2064 if (!pRtlIpv6StringToAddressW)
2065 {
2066 skip("RtlIpv6StringToAddressW not available\n");
2067 /* we can continue, just not test W */
2068 }
2069
2070 if (!pRtlIpv6StringToAddressA)
2071 {
2072 skip("RtlIpv6StringToAddressA not available\n");
2073 return; /* all tests are centered around A, we cannot continue */
2074 }
2075
2076 res = pRtlIpv6StringToAddressA("::", &terminator, &ip);
2077 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2078 if (0)
2079 {
2080 /* any of these crash */
2081 res = pRtlIpv6StringToAddressA(NULL, &terminator, &ip);
2082 ok(res == STATUS_INVALID_PARAMETER, "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2083 res = pRtlIpv6StringToAddressA("::", NULL, &ip);
2084 ok(res == STATUS_INVALID_PARAMETER, "[null terminator] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2085 res = pRtlIpv6StringToAddressA("::", &terminator, NULL);
2086 ok(res == STATUS_INVALID_PARAMETER, "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2087 }
2088
2089 /* sanity check */
2090 ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2091
2092 for (i = 0; i < ipv6_testcount; i++)
2093 {
2094 init_ip6(&ip, NULL);
2095 terminator = (void *)0xdeadbeef;
2096 res = pRtlIpv6StringToAddressA(ipv6_tests[i].address, &terminator, &ip);
2097 compare_RtlIpv6StringToAddressW(ipv6_tests[i].address, (terminator != (void *)0xdeadbeef) ?
2098 (terminator - ipv6_tests[i].address) : -1, &ip, res);
2099
2100 if (ipv6_tests[i].flags & win_broken_6)
2101 {
2102 ok(res == ipv6_tests[i].res || broken(res == STATUS_INVALID_PARAMETER),
2103 "[%s] res = 0x%08x, expected 0x%08x\n",
2104 ipv6_tests[i].address, res, ipv6_tests[i].res);
2105
2106 if (res == STATUS_INVALID_PARAMETER)
2107 continue;
2108 }
2109 else
2110 {
2111 ok(res == ipv6_tests[i].res,
2112 "[%s] res = 0x%08x, expected 0x%08x\n",
2113 ipv6_tests[i].address, res, ipv6_tests[i].res);
2114 }
2115
2116 if (ipv6_tests[i].terminator_offset < 0)
2117 {
2118 ok(terminator == (void *)0xdeadbeef,
2119 "[%s] terminator = %p, expected it not to change\n",
2120 ipv6_tests[i].address, terminator);
2121 }
2122 else if (ipv6_tests[i].flags & win_broken_6)
2123 {
2124 PCSTR expected = ipv6_tests[i].address + ipv6_tests[i].terminator_offset;
2125 ok(terminator == expected || broken(terminator == expected + 2),
2126 "[%s] terminator = %p, expected %p\n",
2127 ipv6_tests[i].address, terminator, expected);
2128 }
2129 else
2130 {
2131 ok(terminator == ipv6_tests[i].address + ipv6_tests[i].terminator_offset,
2132 "[%s] terminator = %p, expected %p\n",
2133 ipv6_tests[i].address, terminator, ipv6_tests[i].address + ipv6_tests[i].terminator_offset);
2134 }
2135
2136 init_ip6(&expected_ip, ipv6_tests[i].ip);
2137 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2138 "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2139 ipv6_tests[i].address,
2140 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2141 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2142 expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2143 expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2144 }
2145 }
2146
2147 static void compare_RtlIpv6StringToAddressExW(PCSTR name_a, const struct in6_addr *addr_a, HRESULT res_a, ULONG scope_a, USHORT port_a)
2148 {
2149 WCHAR name[512];
2150 NTSTATUS res;
2151 IN6_ADDR ip;
2152 ULONG scope = 0xbadf00d;
2153 USHORT port = 0xbeef;
2154
2155 if (!pRtlIpv6StringToAddressExW)
2156 return;
2157
2158 pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
2159
2160 init_ip6(&ip, NULL);
2161 res = pRtlIpv6StringToAddressExW(name, &ip, &scope, &port);
2162
2163 ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2164 ok(scope == scope_a, "[W:%s] scope = 0x%08x, expected 0x%08x\n", name_a, scope, scope_a);
2165 ok(port == port_a, "[W:%s] port = 0x%08x, expected 0x%08x\n", name_a, port, port_a);
2166
2167 ok(!memcmp(&ip, addr_a, sizeof(ip)),
2168 "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2169 name_a,
2170 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2171 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2172 addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2173 addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2174 }
2175
2176 static void test_RtlIpv6StringToAddressEx(void)
2177 {
2178 NTSTATUS res;
2179 IN6_ADDR ip, expected_ip;
2180 ULONG scope;
2181 USHORT port;
2182 static const struct
2183 {
2184 PCSTR address;
2185 NTSTATUS res;
2186 ULONG scope;
2187 USHORT port;
2188 int ip[8];
2189 } ipv6_ex_tests[] =
2190 {
2191 { "[::]", STATUS_SUCCESS, 0, 0,
2192 { 0, 0, 0, 0, 0, 0, 0, 0 } },
2193 { "[::1]:8080", STATUS_SUCCESS, 0, 0x901f,
2194 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2195 { "[::1]:0x80", STATUS_SUCCESS, 0, 0x8000,
2196 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2197 { "[::1]:0X80", STATUS_SUCCESS, 0, 0x8000,
2198 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2199 { "[::1]:080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2200 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2201 { "[::1]:800000000080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2202 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2203 { "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80", STATUS_SUCCESS, 0, 0x5000,
2204 { 0xdcfe, 0x98ba, 0x5476, 0x1032, 0xdcfe, 0x98ba, 0x5476, 0x1032 } },
2205 { "[1080:0:0:0:8:800:200C:417A]:1234", STATUS_SUCCESS, 0, 0xd204,
2206 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2207 { "[3ffe:2a00:100:7031::1]:8080", STATUS_SUCCESS, 0, 0x901f,
2208 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2209 { "[ 3ffe:2a00:100:7031::1]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2210 { -1 } },
2211 { "[3ffe:2a00:100:7031::1 ]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2212 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2213 { "[3ffe:2a00:100:7031::1].8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2214 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2215 { "[1080::8:800:200C:417A]:8080", STATUS_SUCCESS, 0, 0x901f,
2216 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2217 { "[1080::8:800:200C:417A]!8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2218 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2219 { "[::FFFF:129.144.52.38]:80", STATUS_SUCCESS, 0, 0x5000,
2220 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2221 { "[::FFFF:129.144.52.38]:-80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2222 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2223 { "[::FFFF:129.144.52.38]:999999999999", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2224 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2225 { "[::FFFF:129.144.52.38%-8]:80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2226 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2227 { "[::FFFF:129.144.52.38]:80", STATUS_SUCCESS, 0, 0x5000,
2228 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2229 { "[12345::6:7:8]:80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2230 { -1 } },
2231 { "[ff01::8:800:200C:417A%16]:8080", STATUS_SUCCESS, 16, 0x901f,
2232 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2233 { "[ff01::8:800:200C:417A%100]:8080", STATUS_SUCCESS, 100, 0x901f,
2234 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2235 { "[ff01::8:800:200C:417A%1000]:8080", STATUS_SUCCESS, 1000, 0x901f,
2236 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2237 { "[ff01::8:800:200C:417A%10000]:8080", STATUS_SUCCESS, 10000, 0x901f,
2238 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2239 { "[ff01::8:800:200C:417A%1000000]:8080", STATUS_SUCCESS, 1000000, 0x901f,
2240 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2241 { "[ff01::8:800:200C:417A%4294967295]:8080", STATUS_SUCCESS, 0xffffffff, 0x901f,
2242 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2243 { "[ff01::8:800:200C:417A%4294967296]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2244 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2245 { "[ff01::8:800:200C:417A%-1]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2246 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2247 { "[ff01::8:800:200C:417A%0]:8080", STATUS_SUCCESS, 0, 0x901f,
2248 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2249 { "[ff01::8:800:200C:417A%1", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2250 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2251 { "[ff01::8:800:200C:417A%0x1000]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2252 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2253 { "[ff01::8:800:200C:417A/16]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2254 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2255 };
2256 const unsigned int ipv6_ex_testcount = sizeof(ipv6_ex_tests) / sizeof(ipv6_ex_tests[0]);
2257 const char *simple_ip = "::";
2258 unsigned int i;
2259
2260 if (!pRtlIpv6StringToAddressExW)
2261 {
2262 skip("RtlIpv6StringToAddressExW not available\n");
2263 /* we can continue, just not test W */
2264 }
2265
2266 if (!pRtlIpv6StringToAddressExA)
2267 {
2268 skip("RtlIpv6StringToAddressExA not available\n");
2269 return;
2270 }
2271
2272 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, &port);
2273 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2274
2275 init_ip6(&ip, NULL);
2276 init_ip6(&expected_ip, NULL);
2277 scope = 0xbadf00d;
2278 port = 0xbeef;
2279 res = pRtlIpv6StringToAddressExA(NULL, &ip, &scope, &port);
2280 ok(res == STATUS_INVALID_PARAMETER,
2281 "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2282 ok(scope == 0xbadf00d, "[null string] scope = 0x%08x, expected 0xbadf00d\n", scope);
2283 ok(port == 0xbeef, "[null string] port = 0x%08x, expected 0xbeef\n", port);
2284 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2285 "[null string] ip is changed, expected it not to change\n");
2286
2287
2288 init_ip6(&ip, NULL);
2289 scope = 0xbadf00d;
2290 port = 0xbeef;
2291 res = pRtlIpv6StringToAddressExA(simple_ip, NULL, &scope, &port);
2292 ok(res == STATUS_INVALID_PARAMETER,
2293 "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2294 ok(scope == 0xbadf00d, "[null result] scope = 0x%08x, expected 0xbadf00d\n", scope);
2295 ok(port == 0xbeef, "[null result] port = 0x%08x, expected 0xbeef\n", port);
2296 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2297 "[null result] ip is changed, expected it not to change\n");
2298
2299 init_ip6(&ip, NULL);
2300 scope = 0xbadf00d;
2301 port = 0xbeef;
2302 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, NULL, &port);
2303 ok(res == STATUS_INVALID_PARAMETER,
2304 "[null scope] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2305 ok(scope == 0xbadf00d, "[null scope] scope = 0x%08x, expected 0xbadf00d\n", scope);
2306 ok(port == 0xbeef, "[null scope] port = 0x%08x, expected 0xbeef\n", port);
2307 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2308 "[null scope] ip is changed, expected it not to change\n");
2309
2310 init_ip6(&ip, NULL);
2311 scope = 0xbadf00d;
2312 port = 0xbeef;
2313 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, NULL);
2314 ok(res == STATUS_INVALID_PARAMETER,
2315 "[null port] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2316 ok(scope == 0xbadf00d, "[null port] scope = 0x%08x, expected 0xbadf00d\n", scope);
2317 ok(port == 0xbeef, "[null port] port = 0x%08x, expected 0xbeef\n", port);
2318 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2319 "[null port] ip is changed, expected it not to change\n");
2320
2321 /* sanity check */
2322 ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2323
2324 /* first we run all ip related tests, to make sure someone didnt accidentally reimplement instead of re-use. */
2325 for (i = 0; i < ipv6_testcount; i++)
2326 {
2327 ULONG scope = 0xbadf00d;
2328 USHORT port = 0xbeef;
2329 NTSTATUS expect_ret = (ipv6_tests[i].flags & ex_fail_6) ? STATUS_INVALID_PARAMETER : ipv6_tests[i].res;
2330
2331 if (ipv6_tests[i].flags & ex_skip_6)
2332 continue;
2333
2334 init_ip6(&ip, NULL);
2335 res = pRtlIpv6StringToAddressExA(ipv6_tests[i].address, &ip, &scope, &port);
2336 compare_RtlIpv6StringToAddressExW(ipv6_tests[i].address, &ip, res, scope, port);
2337
2338 /* make sure nothing was changed if this function fails. */
2339 if (res == STATUS_INVALID_PARAMETER)
2340 {
2341 ok(scope == 0xbadf00d, "[%s] scope = 0x%08x, expected 0xbadf00d\n",
2342 ipv6_tests[i].address, scope);
2343 ok(port == 0xbeef, "[%s] port = 0x%08x, expected 0xbeef\n",
2344 ipv6_tests[i].address, port);
2345 }
2346 else
2347 {
2348 ok(scope != 0xbadf00d, "[%s] scope = 0x%08x, not expected 0xbadf00d\n",
2349 ipv6_tests[i].address, scope);
2350 ok(port != 0xbeef, "[%s] port = 0x%08x, not expected 0xbeef\n",
2351 ipv6_tests[i].address, port);
2352 }
2353
2354 if (ipv6_tests[i].flags & win_broken_6)
2355 {
2356 ok(res == expect_ret || broken(res == STATUS_INVALID_PARAMETER),
2357 "[%s] res = 0x%08x, expected 0x%08x\n", ipv6_tests[i].address, res, expect_ret);
2358
2359 if (res == STATUS_INVALID_PARAMETER)
2360 continue;
2361 }
2362 else
2363 {
2364 ok(res == expect_ret, "[%s] res = 0x%08x, expected 0x%08x\n",
2365 ipv6_tests[i].address, res, expect_ret);
2366 }
2367
2368 /* If ex fails but non-ex does not we cannot check if the part that is converted
2369 before it failed was correct, since there is no data for it in the table. */
2370 if (res == expect_ret)
2371 {
2372 init_ip6(&expected_ip, ipv6_tests[i].ip);
2373 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2374 "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2375 ipv6_tests[i].address,
2376 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2377 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2378 expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2379 expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2380 }
2381 }
2382
2383 /* now we run scope / port related tests */
2384 for (i = 0; i < ipv6_ex_testcount; i++)
2385 {
2386 scope = 0xbadf00d;
2387 port = 0xbeef;
2388 init_ip6(&ip, NULL);
2389 res = pRtlIpv6StringToAddressExA(ipv6_ex_tests[i].address, &ip, &scope, &port);