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