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