[NTDLL_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[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))
2615 {
2616 chunk_size = (*(WORD *)compressed & 0xFFF) + 1;
2617 if (compressed_size < sizeof(WORD) + chunk_size)
2618 return TRUE;
2619 if (!check_all)
2620 break;
2621 compressed += sizeof(WORD) + chunk_size;
2622 compressed_size -= sizeof(WORD) + chunk_size;
2623 }
2624
2625 return FALSE;
2626 }
2627
2628 #define DECOMPRESS_BROKEN_FRAGMENT 1 /* < Win 7 */
2629 #define DECOMPRESS_BROKEN_TRUNCATED 2 /* broken on all machines */
2630
2631 static void test_RtlDecompressBuffer(void)
2632 {
2633 static const struct
2634 {
2635 UCHAR compressed[32];
2636 ULONG compressed_size;
2637 NTSTATUS status;
2638 UCHAR uncompressed[32];
2639 ULONG uncompressed_size;
2640 DWORD broken_flags;
2641 }
2642 test_lznt[] =
2643 {
2644 /* 4 byte uncompressed chunk */
2645 {
2646 {0x03, 0x30, 'W', 'i', 'n', 'e'},
2647 6,
2648 STATUS_SUCCESS,
2649 "Wine",
2650 4,
2651 DECOMPRESS_BROKEN_FRAGMENT
2652 },
2653 /* 8 byte uncompressed chunk */
2654 {
2655 {0x07, 0x30, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2656 10,
2657 STATUS_SUCCESS,
2658 "WineWine",
2659 8,
2660 DECOMPRESS_BROKEN_FRAGMENT
2661 },
2662 /* 4 byte compressed chunk */
2663 {
2664 {0x04, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2665 7,
2666 STATUS_SUCCESS,
2667 "Wine",
2668 4
2669 },
2670 /* 8 byte compressed chunk */
2671 {
2672 {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2673 11,
2674 STATUS_SUCCESS,
2675 "WineWine",
2676 8
2677 },
2678 /* compressed chunk using backwards reference */
2679 {
2680 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x01, 0x30},
2681 9,
2682 STATUS_SUCCESS,
2683 "WineWine",
2684 8,
2685 DECOMPRESS_BROKEN_TRUNCATED
2686 },
2687 /* compressed chunk using backwards reference with length > bytes_read */
2688 {
2689 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x30},
2690 9,
2691 STATUS_SUCCESS,
2692 "WineWineWine",
2693 12,
2694 DECOMPRESS_BROKEN_TRUNCATED
2695 },
2696 /* same as above, but unused bits != 0 */
2697 {
2698 {0x06, 0xB0, 0x30, 'W', 'i', 'n', 'e', 0x01, 0x30},
2699 9,
2700 STATUS_SUCCESS,
2701 "WineWine",
2702 8,
2703 DECOMPRESS_BROKEN_TRUNCATED
2704 },
2705 /* compressed chunk without backwards reference and unused bits != 0 */
2706 {
2707 {0x01, 0xB0, 0x02, 'W'},
2708 4,
2709 STATUS_SUCCESS,
2710 "W",
2711 1
2712 },
2713 /* termination sequence after first chunk */
2714 {
2715 {0x03, 0x30, 'W', 'i', 'n', 'e', 0x00, 0x00, 0x03, 0x30, 'W', 'i', 'n', 'e'},
2716 14,
2717 STATUS_SUCCESS,
2718 "Wine",
2719 4,
2720 DECOMPRESS_BROKEN_FRAGMENT
2721 },
2722 /* compressed chunk using backwards reference with 4 bit offset, 12 bit length */
2723 {
2724 {0x14, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2725 0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2726 0x01, 0x01, 0xF0},
2727 23,
2728 STATUS_SUCCESS,
2729 "ABCDEFGHIJKLMNOPABCD",
2730 20,
2731 DECOMPRESS_BROKEN_TRUNCATED
2732 },
2733 /* compressed chunk using backwards reference with 5 bit offset, 11 bit length */
2734 {
2735 {0x15, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2736 0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2737 0x02, 'A', 0x00, 0x78},
2738 24,
2739 STATUS_SUCCESS,
2740 "ABCDEFGHIJKLMNOPABCD",
2741 20,
2742 DECOMPRESS_BROKEN_TRUNCATED
2743 },
2744 /* uncompressed chunk with invalid magic */
2745 {
2746 {0x03, 0x20, 'W', 'i', 'n', 'e'},
2747 6,
2748 STATUS_SUCCESS,
2749 "Wine",
2750 4,
2751 DECOMPRESS_BROKEN_FRAGMENT
2752 },
2753 /* compressed chunk with invalid magic */
2754 {
2755 {0x04, 0xA0, 0x00, 'W', 'i', 'n', 'e'},
2756 7,
2757 STATUS_SUCCESS,
2758 "Wine",
2759 4
2760 },
2761 /* garbage byte after end of buffer */
2762 {
2763 {0x00, 0xB0, 0x02, 0x01},
2764 4,
2765 STATUS_SUCCESS,
2766 "",
2767 0
2768 },
2769 /* empty compressed chunk */
2770 {
2771 {0x00, 0xB0, 0x00},
2772 3,
2773 STATUS_SUCCESS,
2774 "",
2775 0
2776 },
2777 /* empty compressed chunk with unused bits != 0 */
2778 {
2779 {0x00, 0xB0, 0x01},
2780 3,
2781 STATUS_SUCCESS,
2782 "",
2783 0
2784 },
2785 /* empty input buffer */
2786 {
2787 {0},
2788 0,
2789 STATUS_BAD_COMPRESSION_BUFFER,
2790 },
2791 /* incomplete chunk header */
2792 {
2793 {0x01},
2794 1,
2795 STATUS_BAD_COMPRESSION_BUFFER
2796 },
2797 /* incomplete chunk header */
2798 {
2799 {0x00, 0x30},
2800 2,
2801 STATUS_BAD_COMPRESSION_BUFFER
2802 },
2803 /* compressed chunk with invalid backwards reference */
2804 {
2805 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x40},
2806 9,
2807 STATUS_BAD_COMPRESSION_BUFFER
2808 },
2809 /* compressed chunk with incomplete backwards reference */
2810 {
2811 {0x05, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05},
2812 8,
2813 STATUS_BAD_COMPRESSION_BUFFER
2814 },
2815 /* incomplete uncompressed chunk */
2816 {
2817 {0x07, 0x30, 'W', 'i', 'n', 'e'},
2818 6,
2819 STATUS_BAD_COMPRESSION_BUFFER
2820 },
2821 /* incomplete compressed chunk */
2822 {
2823 {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2824 7,
2825 STATUS_BAD_COMPRESSION_BUFFER
2826 },
2827 /* two compressed chunks, the second one incomplete */
2828 {
2829 {0x00, 0xB0, 0x02, 0x00, 0xB0},
2830 5,
2831 STATUS_BAD_COMPRESSION_BUFFER,
2832 }
2833 };
2834
2835 static UCHAR buf[0x2000], workspace[0x1000];
2836 NTSTATUS status, expected_status;
2837 ULONG final_size;
2838 int i;
2839
2840 if (!pRtlDecompressBuffer || !pRtlDecompressFragment)
2841 {
2842 win_skip("RtlDecompressBuffer or RtlDecompressFragment is not available\n");
2843 return;
2844 }
2845
2846 /* test compression format / engine */
2847 final_size = 0xdeadbeef;
2848 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf), test_lznt[0].compressed,
2849 test_lznt[0].compressed_size, &final_size);
2850 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2851 ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2852
2853 final_size = 0xdeadbeef;
2854 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf), test_lznt[0].compressed,
2855 test_lznt[0].compressed_size, &final_size);
2856 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2857 ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2858
2859 final_size = 0xdeadbeef;
2860 status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf), test_lznt[0].compressed,
2861 test_lznt[0].compressed_size, &final_size);
2862 ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
2863 ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2864
2865 /* regular tests for RtlDecompressBuffer */
2866 for (i = 0; i < sizeof(test_lznt) / sizeof(test_lznt[0]); i++)
2867 {
2868 trace("Running test %d (compressed_size=%u, uncompressed_size=%u, status=0x%08x)\n",
2869 i, test_lznt[i].compressed_size, test_lznt[i].uncompressed_size, test_lznt[i].status);
2870
2871 /* test with very big buffer */
2872 final_size = 0xdeadbeef;
2873 memset(buf, 0x11, sizeof(buf));
2874 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2875 test_lznt[i].compressed_size, &final_size);
2876 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
2877 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
2878 if (!status)
2879 {
2880 ok(final_size == test_lznt[i].uncompressed_size,
2881 "%d: got wrong final_size %u\n", i, final_size);
2882 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2883 "%d: got wrong decoded data\n", i);
2884 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2885 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2886 }
2887
2888 /* test that modifier for compression engine is ignored */
2889 final_size = 0xdeadbeef;
2890 memset(buf, 0x11, sizeof(buf));
2891 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buf, sizeof(buf),
2892 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2893 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
2894 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
2895 if (!status)
2896 {
2897 ok(final_size == test_lznt[i].uncompressed_size,
2898 "%d: got wrong final_size %u\n", i, final_size);
2899 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2900 "%d: got wrong decoded data\n", i);
2901 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2902 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2903 }
2904
2905 /* test with expected output size */
2906 if (test_lznt[i].uncompressed_size > 0)
2907 {
2908 final_size = 0xdeadbeef;
2909 memset(buf, 0x11, sizeof(buf));
2910 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size,
2911 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2912 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2913 if (!status)
2914 {
2915 ok(final_size == test_lznt[i].uncompressed_size,
2916 "%d: got wrong final_size %u\n", i, final_size);
2917 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2918 "%d: got wrong decoded data\n", i);
2919 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2920 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2921 }
2922 }
2923
2924 /* test with smaller output size */
2925 if (test_lznt[i].uncompressed_size > 1)
2926 {
2927 final_size = 0xdeadbeef;
2928 memset(buf, 0x11, sizeof(buf));
2929 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size - 1,
2930 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2931 if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_TRUNCATED)
2932 todo_wine
2933 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2934 else
2935 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2936 if (!status)
2937 {
2938 ok(final_size == test_lznt[i].uncompressed_size - 1,
2939 "%d: got wrong final_size %u\n", i, final_size);
2940 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size - 1),
2941 "%d: got wrong decoded data\n", i);
2942 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
2943 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1);
2944 }
2945 }
2946
2947 /* test with zero output size */
2948 final_size = 0xdeadbeef;
2949 memset(buf, 0x11, sizeof(buf));
2950 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_lznt[i].compressed,
2951 test_lznt[i].compressed_size, &final_size);
2952 if (is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, FALSE))
2953 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2954 else
2955 {
2956 ok(status == STATUS_SUCCESS, "%d: got wrong status 0x%08x\n", i, status);
2957 ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size);
2958 ok(buf[0] == 0x11, "%d: buf[0] was modified\n", i);
2959 }
2960
2961 /* test RtlDecompressFragment with offset = 0 */
2962 final_size = 0xdeadbeef;
2963 memset(buf, 0x11, sizeof(buf));
2964 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2965 test_lznt[i].compressed_size, 0, &final_size, workspace);
2966 if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
2967 todo_wine
2968 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2969 else
2970 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2971 if (!status)
2972 {
2973 ok(final_size == test_lznt[i].uncompressed_size,
2974 "%d: got wrong final_size %u\n", i, final_size);
2975 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2976 "%d: got wrong decoded data\n", i);
2977 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2978 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2979 }
2980
2981 /* test RtlDecompressFragment with offset = 1 */
2982 final_size = 0xdeadbeef;
2983 memset(buf, 0x11, sizeof(buf));
2984 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2985 test_lznt[i].compressed_size, 1, &final_size, workspace);
2986 if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
2987 todo_wine
2988 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2989 else
2990 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2991 if (!status)
2992 {
2993 if (test_lznt[i].uncompressed_size == 0)
2994 {
2995 todo_wine
2996 ok(final_size == 4095, "%d: got wrong final_size %u\n", i, final_size);
2997 /* Buffer doesn't contain any useful value on Windows */
2998 ok(buf[4095] == 0x11, "%d: buf[4095] was modified\n", i);
2999 }
3000 else
3001 {
3002 ok(final_size == test_lznt[i].uncompressed_size - 1,
3003 "%d: got wrong final_size %u\n", i, final_size);
3004 ok(!memcmp(buf, test_lznt[i].uncompressed + 1, test_lznt[i].uncompressed_size - 1),
3005 "%d: got wrong decoded data\n", i);
3006 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
3007 "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1);
3008 }
3009 }
3010
3011 /* test RtlDecompressFragment with offset = 4095 */
3012 final_size = 0xdeadbeef;
3013 memset(buf, 0x11, sizeof(buf));
3014 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3015 test_lznt[i].compressed_size, 4095, &final_size, workspace);
3016 if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
3017 todo_wine
3018 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
3019 else
3020 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
3021 if (!status)
3022 {
3023 todo_wine
3024 ok(final_size == 1, "%d: got wrong final_size %u\n", i, final_size);
3025 todo_wine
3026 ok(buf[0] == 0, "%d: padding is not zero\n", i);
3027 ok(buf[1] == 0x11, "%d: buf[1] was modified\n", i);
3028 }
3029
3030 /* test RtlDecompressFragment with offset = 4096 */
3031 final_size = 0xdeadbeef;
3032 memset(buf, 0x11, sizeof(buf));
3033 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3034 test_lznt[i].compressed_size, 4096, &final_size, workspace);
3035 expected_status = is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, TRUE) ?
3036 test_lznt[i].status : STATUS_SUCCESS;
3037 ok(status == expected_status, "%d: got wrong status 0x%08x, expected 0x%08x\n", i, status, expected_status);
3038 if (!status)
3039 {
3040 ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size);
3041 ok(buf[0] == 0x11, "%d: buf[4096] was modified\n", i);
3042 }
3043 }
3044 }
3045
3046 #undef DECOMPRESS_BROKEN_FRAGMENT
3047 #undef DECOMPRESS_BROKEN_TRUNCATED
3048
3049 struct critsect_locked_info
3050 {
3051 CRITICAL_SECTION crit;
3052 HANDLE semaphores[2];
3053 };
3054
3055 static DWORD WINAPI critsect_locked_thread(void *param)
3056 {
3057 struct critsect_locked_info *info = param;
3058 DWORD ret;
3059
3060 ret = pRtlIsCriticalSectionLocked(&info->crit);
3061 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3062 ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3063 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3064
3065 ReleaseSemaphore(info->semaphores[0], 1, NULL);
3066 ret = WaitForSingleObject(info->semaphores[1], 1000);
3067 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3068
3069 ret = pRtlIsCriticalSectionLocked(&info->crit);
3070 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3071 ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3072 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3073
3074 EnterCriticalSection(&info->crit);
3075
3076 ret = pRtlIsCriticalSectionLocked(&info->crit);
3077 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3078 ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3079 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3080
3081 ReleaseSemaphore(info->semaphores[0], 1, NULL);
3082 ret = WaitForSingleObject(info->semaphores[1], 1000);
3083 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3084
3085 LeaveCriticalSection(&info->crit);
3086 return 0;
3087 }
3088
3089 static void test_RtlIsCriticalSectionLocked(void)
3090 {
3091 struct critsect_locked_info info;
3092 HANDLE thread;
3093 BOOL ret;
3094
3095 if (!pRtlIsCriticalSectionLocked || !pRtlIsCriticalSectionLockedByThread)
3096 {
3097 win_skip("skipping RtlIsCriticalSectionLocked tests, required functions not available\n");
3098 return;
3099 }
3100
3101 InitializeCriticalSection(&info.crit);
3102 info.semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
3103 ok(info.semaphores[0] != NULL, "CreateSemaphore failed with %u\n", GetLastError());
3104 info.semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
3105 ok(info.semaphores[1] != NULL, "CreateSemaphore failed with %u\n", GetLastError());
3106
3107 ret = pRtlIsCriticalSectionLocked(&info.crit);
3108 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3109 ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3110 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3111
3112 EnterCriticalSection(&info.crit);
3113
3114 ret = pRtlIsCriticalSectionLocked(&info.crit);
3115 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3116 ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3117 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3118
3119 thread = CreateThread(NULL, 0, critsect_locked_thread, &info, 0, NULL);
3120 ok(thread != NULL, "CreateThread failed with %u\n", GetLastError());
3121 ret = WaitForSingleObject(info.semaphores[0], 1000);
3122 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3123
3124 LeaveCriticalSection(&info.crit);
3125
3126 ReleaseSemaphore(info.semaphores[1], 1, NULL);
3127 ret = WaitForSingleObject(info.semaphores[0], 1000);
3128 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3129
3130 ret = pRtlIsCriticalSectionLocked(&info.crit);
3131 ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3132 ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3133 ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3134
3135 ReleaseSemaphore(info.semaphores[1], 1, NULL);
3136 ret = WaitForSingleObject(thread, 1000);
3137 ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3138
3139 CloseHandle(thread);
3140 CloseHandle(info.semaphores[0]);
3141 CloseHandle(info.semaphores[1]);
3142 DeleteCriticalSection(&info.crit);
3143 }
3144
3145 static void test_RtlInitializeCriticalSectionEx(void)
3146 {
3147 static const CRITICAL_SECTION_DEBUG *no_debug = (void *)~(ULONG_PTR)0;
3148 CRITICAL_SECTION cs;
3149
3150 if (!pRtlInitializeCriticalSectionEx)
3151 {
3152 win_skip("RtlInitializeCriticalSectionEx is not available\n");
3153 return;
3154 }
3155
3156 memset(&cs, 0x11, sizeof(cs));
3157 pRtlInitializeCriticalSectionEx(&cs, 0, 0);
3158 ok((cs.DebugInfo != NULL && cs.DebugInfo != no_debug) || broken(cs.DebugInfo == no_debug) /* >= Win 8 */,
3159 "expected DebugInfo != NULL and DebugInfo != ~0, got %p\n", cs.DebugInfo);
3160 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3161 ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3162 ok(cs.LockSemaphore == NULL, "expected LockSemaphore == NULL, got %p\n", cs.LockSemaphore);
3163 ok(cs.SpinCount == 0 || broken(cs.SpinCount != 0) /* >= Win 8 */,
3164 "expected SpinCount == 0, got %ld\n", cs.SpinCount);
3165 RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
3166
3167 memset(&cs, 0x11, sizeof(cs));
3168 pRtlInitializeCriticalSectionEx(&cs, 0, RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO);
3169 todo_wine
3170 ok(cs.DebugInfo == no_debug, "expected DebugInfo == ~0, got %p\n", cs.DebugInfo);
3171 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3172 ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3173 ok(cs.LockSemaphore == NULL, "expected LockSemaphore == NULL, got %p\n", cs.LockSemaphore);
3174 ok(cs.SpinCount == 0 || broken(cs.SpinCount != 0) /* >= Win 8 */,
3175 "expected SpinCount == 0, got %ld\n", cs.SpinCount);
3176 RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
3177 }
3178
3179 static void test_RtlLeaveCriticalSection(void)
3180 {
3181 RTL_CRITICAL_SECTION cs;
3182 NTSTATUS status;
3183
3184 if (!pRtlInitializeCriticalSectionEx)
3185 return; /* Skip winxp */
3186
3187 status = RtlInitializeCriticalSection(&cs);
3188 ok(!status, "RtlInitializeCriticalSection failed: %x\n", status);
3189
3190 status = RtlEnterCriticalSection(&cs);
3191 ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
3192 todo_wine
3193 ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
3194 ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
3195 ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
3196
3197 status = RtlLeaveCriticalSection(&cs);
3198 ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3199 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3200 ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3201 ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3202
3203 /*
3204 * Trying to leave a section that wasn't acquired modifies RecursionCount to an invalid value,
3205 * but doesn't modify LockCount so that an attempt to enter the section later will work.
3206 */
3207 status = RtlLeaveCriticalSection(&cs);
3208 ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3209 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3210 ok(cs.RecursionCount == -1, "expected RecursionCount == -1, got %d\n", cs.RecursionCount);
3211 ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3212
3213 /* and again */
3214 status = RtlLeaveCriticalSection(&cs);
3215 ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3216 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3217 ok(cs.RecursionCount == -2, "expected RecursionCount == -2, got %d\n", cs.RecursionCount);
3218 ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3219
3220 /* entering section fixes RecursionCount */
3221 status = RtlEnterCriticalSection(&cs);
3222 ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
3223 todo_wine
3224 ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
3225 ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
3226 ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
3227
3228 status = RtlLeaveCriticalSection(&cs);
3229 ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3230 ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3231 ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3232 ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3233
3234 status = RtlDeleteCriticalSection(&cs);
3235 ok(!status, "RtlDeleteCriticalSection failed: %x\n", status);
3236 }
3237
3238 struct ldr_enum_context
3239 {
3240 BOOL abort;
3241 BOOL found;
3242 int count;
3243 };
3244
3245 static void WINAPI ldr_enum_callback(LDR_MODULE *module, void *context, BOOLEAN *stop)
3246 {
3247 static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
3248 struct ldr_enum_context *ctx = context;
3249
3250 if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
3251 ctx->found = TRUE;
3252
3253 ctx->count++;
3254 *stop = ctx->abort;
3255 }
3256
3257 static void test_LdrEnumerateLoadedModules(void)
3258 {
3259 struct ldr_enum_context ctx;
3260 NTSTATUS status;
3261
3262 if (!pLdrEnumerateLoadedModules)
3263 {
3264 win_skip("LdrEnumerateLoadedModules not available\n");
3265 return;
3266 }
3267
3268 ctx.abort = FALSE;
3269 ctx.found = FALSE;
3270 ctx.count = 0;
3271 status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
3272 ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
3273 ok(ctx.count > 1, "Expected more than one module, got %d\n", ctx.count);
3274 ok(ctx.found, "Could not find ntdll in list of modules\n");
3275
3276 ctx.abort = TRUE;
3277 ctx.count = 0;
3278 status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
3279 ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
3280 ok(ctx.count == 1, "Expected exactly one module, got %d\n", ctx.count);
3281
3282 status = pLdrEnumerateLoadedModules((void *)0x1, ldr_enum_callback, (void *)0xdeadbeef);
3283 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3284
3285 status = pLdrEnumerateLoadedModules((void *)0xdeadbeef, ldr_enum_callback, (void *)0xdeadbeef);
3286 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3287
3288 status = pLdrEnumerateLoadedModules(NULL, NULL, (void *)0xdeadbeef);
3289 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3290 }
3291
3292 static void test_RtlMakeSelfRelativeSD(void)
3293 {
3294 char buf[sizeof(SECURITY_DESCRIPTOR_RELATIVE) + 4];
3295 SECURITY_DESCRIPTOR_RELATIVE *sd_rel = (SECURITY_DESCRIPTOR_RELATIVE *)buf;
3296 SECURITY_DESCRIPTOR sd;
3297 NTSTATUS status;
3298 DWORD len;
3299
3300 if (!pRtlMakeSelfRelativeSD || !pRtlAbsoluteToSelfRelativeSD)
3301 {
3302 win_skip( "RtlMakeSelfRelativeSD/RtlAbsoluteToSelfRelativeSD not available\n" );
3303 return;
3304 }
3305
3306 memset( &sd, 0, sizeof(sd) );
3307 sd.Revision = SECURITY_DESCRIPTOR_REVISION;
3308
3309 len = 0;
3310 status = pRtlMakeSelfRelativeSD( &sd, NULL, &len );
3311 ok( status == STATUS_BUFFER_TOO_SMALL, "got %08x\n", status );
3312 ok( len == sizeof(*sd_rel), "got %u\n", len );
3313
3314 len += 4;
3315 status = pRtlMakeSelfRelativeSD( &sd, sd_rel, &len );
3316 ok( status == STATUS_SUCCESS, "got %08x\n", status );
3317 ok( len == sizeof(*sd_rel) + 4, "got %u\n", len );
3318
3319 len = 0;
3320 status = pRtlAbsoluteToSelfRelativeSD( &sd, NULL, &len );
3321 ok( status == STATUS_BUFFER_TOO_SMALL, "got %08x\n", status );
3322 ok( len == sizeof(*sd_rel), "got %u\n", len );
3323
3324 len += 4;
3325 status = pRtlAbsoluteToSelfRelativeSD( &sd, sd_rel, &len );
3326 ok( status == STATUS_SUCCESS, "got %08x\n", status );
3327 ok( len == sizeof(*sd_rel) + 4, "got %u\n", len );
3328
3329 sd.Control = SE_SELF_RELATIVE;
3330 status = pRtlMakeSelfRelativeSD( &sd, sd_rel, &len );
3331 ok( status == STATUS_SUCCESS, "got %08x\n", status );
3332 ok( len == sizeof(*sd_rel) + 4, "got %u\n", len );
3333
3334 status = pRtlAbsoluteToSelfRelativeSD( &sd, sd_rel, &len );
3335 ok( status == STATUS_BAD_DESCRIPTOR_FORMAT, "got %08x\n", status );
3336 }
3337
3338 static void test_RtlQueryPackageIdentity(void)
3339 {
3340 const WCHAR programW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
3341 'P','h','o','t','o','s','_','8','w','e','k','y','b','3','d','8','b','b','w','e','!','A','p','p',0};
3342 const WCHAR fullnameW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
3343 'P','h','o','t','o','s', 0};
3344 const WCHAR appidW[] = {'A','p','p',0};
3345 IApplicationActivationManager *manager;
3346 WCHAR buf1[MAX_PATH], buf2[MAX_PATH];
3347 HANDLE process, token;
3348 SIZE_T size1, size2;
3349 NTSTATUS status;
3350 DWORD processid;
3351 HRESULT hr;
3352 BOOL ret;
3353
3354 if (!pRtlQueryPackageIdentity)
3355 {
3356 win_skip("RtlQueryPackageIdentity not available\n");
3357 return;
3358 }
3359
3360 size1 = size2 = MAX_PATH * sizeof(WCHAR);
3361 status = pRtlQueryPackageIdentity((HANDLE)~(ULONG_PTR)3, buf1, &size1, buf2, &size2, NULL);
3362 ok(status == STATUS_NOT_FOUND, "expected STATUS_NOT_FOUND, got %08x\n", status);
3363
3364 CoInitializeEx(0, COINIT_APARTMENTTHREADED);
3365 hr = CoCreateInstance(&CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER,
3366 &IID_IApplicationActivationManager, (void **)&manager);
3367 if (FAILED(hr))
3368 {
3369 todo_wine win_skip("Failed to create ApplicationActivationManager (%x)\n", hr);
3370 goto done;
3371 }
3372
3373 hr = IApplicationActivationManager_ActivateApplication(manager, programW, NULL,
3374 AO_NOERRORUI, &processid);
3375 if (FAILED(hr))
3376 {
3377 todo_wine win_skip("Failed to start program (%x)\n", hr);
3378 IApplicationActivationManager_Release(manager);
3379 goto done;
3380 }
3381
3382 process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, FALSE, processid);
3383 ok(process != NULL, "OpenProcess failed with %u\n", GetLastError());
3384 ret = OpenProcessToken(process, TOKEN_QUERY, &token);
3385 ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
3386
3387 size1 = size2 = MAX_PATH * sizeof(WCHAR);
3388 status = pRtlQueryPackageIdentity(token, buf1, &size1, buf2, &size2, NULL);
3389 ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
3390
3391 ok(!memcmp(buf1, fullnameW, sizeof(fullnameW) - sizeof(WCHAR)),
3392 "Expected buf1 to begin with %s, got %s\n", wine_dbgstr_w(fullnameW), wine_dbgstr_w(buf1));
3393 ok(size1 >= sizeof(WCHAR) && !(size1 % sizeof(WCHAR)), "Unexpected size1 = %lu\n", size1);
3394 ok(buf1[size1 / sizeof(WCHAR) - 1] == 0, "Expected buf1[%lu] == 0\n", size1 / sizeof(WCHAR) - 1);
3395
3396 ok(!lstrcmpW(buf2, appidW), "Expected buf2 to be %s, got %s\n", wine_dbgstr_w(appidW), wine_dbgstr_w(buf2));
3397 ok(size2 >= sizeof(WCHAR) && !(size2 % sizeof(WCHAR)), "Unexpected size2 = %lu\n", size2);
3398 ok(buf2[size2 / sizeof(WCHAR) - 1] == 0, "Expected buf2[%lu] == 0\n", size2 / sizeof(WCHAR) - 1);
3399
3400 CloseHandle(token);
3401 TerminateProcess(process, 0);
3402 CloseHandle(process);
3403
3404 done:
3405 CoUninitialize();
3406 }
3407
3408 static DWORD (CALLBACK *orig_entry)(HMODULE,DWORD,LPVOID);
3409 static DWORD *dll_main_data;
3410
3411 static inline void *get_rva( HMODULE module, DWORD va )
3412 {
3413 return (void *)((char *)module + va);
3414 }
3415
3416 static void CALLBACK ldr_notify_callback1(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3417 {
3418 const IMAGE_IMPORT_DESCRIPTOR *imports;
3419 const IMAGE_THUNK_DATA *import_list;
3420 IMAGE_THUNK_DATA *thunk_list;
3421 DWORD *calls = context;
3422 LIST_ENTRY *mark;
3423 LDR_MODULE *mod;
3424 ULONG size;
3425 int i, j;
3426
3427 *calls <<= 4;
3428 *calls |= reason;
3429
3430 ok(data->Loaded.Flags == 0, "Expected flags 0, got %x\n", data->Loaded.Flags);
3431 ok(!lstrcmpiW(data->Loaded.BaseDllName->Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
3432 wine_dbgstr_w(data->Loaded.BaseDllName->Buffer));
3433 ok(!!data->Loaded.DllBase, "Expected non zero base address\n");
3434 ok(data->Loaded.SizeOfImage, "Expected non zero image size\n");
3435
3436 /* expect module to be last module listed in LdrData load order list */
3437 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3438 mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3439 ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3440 data->Loaded.DllBase, mod->BaseAddress);
3441 ok(!lstrcmpiW(mod->BaseDllName.Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
3442 wine_dbgstr_w(mod->BaseDllName.Buffer));
3443
3444 /* show that imports have already been resolved */
3445 imports = RtlImageDirectoryEntryToData(data->Loaded.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
3446 ok(!!imports, "Expected dll to have imports\n");
3447
3448 for (i = 0; imports[i].Name; i++)
3449 {
3450 thunk_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].FirstThunk);
3451 if (imports[i].OriginalFirstThunk)
3452 import_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].OriginalFirstThunk);
3453 else
3454 import_list = thunk_list;
3455
3456 for (j = 0; import_list[j].u1.Ordinal; j++)
3457 {
3458 ok(thunk_list[j].u1.AddressOfData > data->Loaded.SizeOfImage,
3459 "Import has not been resolved: %p\n", (void*)thunk_list[j].u1.Function);
3460 }
3461 }
3462 }
3463
3464 static void CALLBACK ldr_notify_callback2(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3465 {
3466 DWORD *calls = context;
3467 *calls <<= 4;
3468 *calls |= reason + 2;
3469 }
3470
3471 static BOOL WINAPI fake_dll_main(HINSTANCE instance, DWORD reason, void* reserved)
3472 {
3473 if (reason == DLL_PROCESS_ATTACH)
3474 {
3475 *dll_main_data <<= 4;
3476 *dll_main_data |= 3;
3477 }
3478 else if (reason == DLL_PROCESS_DETACH)
3479 {
3480 *dll_main_data <<= 4;
3481 *dll_main_data |= 4;
3482 }
3483 return orig_entry(instance, reason, reserved);
3484 }
3485
3486 static void CALLBACK ldr_notify_callback_dll_main(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3487 {
3488 DWORD *calls = context;
3489 LIST_ENTRY *mark;
3490 LDR_MODULE *mod;
3491
3492 *calls <<= 4;
3493 *calls |= reason;
3494
3495 if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3496 return;
3497
3498 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3499 mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3500 ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3501 data->Loaded.DllBase, mod->BaseAddress);
3502 if (mod->BaseAddress != data->Loaded.DllBase)
3503 return;
3504
3505 orig_entry = mod->EntryPoint;
3506 mod->EntryPoint = fake_dll_main;
3507 dll_main_data = calls;
3508 }
3509
3510 static BOOL WINAPI fake_dll_main_fail(HINSTANCE instance, DWORD reason, void* reserved)
3511 {
3512 if (reason == DLL_PROCESS_ATTACH)
3513 {
3514 *dll_main_data <<= 4;
3515 *dll_main_data |= 3;
3516 }
3517 else if (reason == DLL_PROCESS_DETACH)
3518 {
3519 *dll_main_data <<= 4;
3520 *dll_main_data |= 4;
3521 }
3522 return FALSE;
3523 }
3524
3525 static void CALLBACK ldr_notify_callback_fail(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3526 {
3527 DWORD *calls = context;
3528 LIST_ENTRY *mark;
3529 LDR_MODULE *mod;
3530
3531 *calls <<= 4;
3532 *calls |= reason;
3533
3534 if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3535 return;
3536
3537 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3538 mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3539 ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3540 data->Loaded.DllBase, mod->BaseAddress);
3541 if (mod->BaseAddress != data->Loaded.DllBase)
3542 return;
3543
3544 orig_entry = mod->EntryPoint;
3545 mod->EntryPoint = fake_dll_main_fail;
3546 dll_main_data = calls;
3547 }
3548
3549 static void CALLBACK ldr_notify_callback_imports(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3550 {
3551 DWORD *calls = context;
3552
3553 if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3554 return;
3555
3556 if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, crypt32dllW))
3557 {
3558 *calls <<= 4;
3559 *calls |= 1;
3560 }
3561
3562 if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, wintrustdllW))
3563 {
3564 *calls <<= 4;
3565 *calls |= 2;
3566 }
3567 }
3568
3569 static void test_LdrRegisterDllNotification(void)
3570 {
3571 void *cookie, *cookie2;
3572 NTSTATUS status;
3573 HMODULE mod;
3574 DWORD calls;
3575
3576 if (!pLdrRegisterDllNotification || !pLdrUnregisterDllNotification)
3577 {
3578 win_skip("Ldr(Un)RegisterDllNotification not available\n");
3579 return;
3580 }
3581
3582 /* generic test */
3583 status = pLdrRegisterDllNotification(0, ldr_notify_callback1, &calls, &cookie);
3584 ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3585
3586 calls = 0;
3587 mod = LoadLibraryW(ws2_32dllW);
3588 ok(!!mod, "Failed to load library: %d\n", GetLastError());
3589 ok(calls == LDR_DLL_NOTIFICATION_REASON_LOADED, "Expected LDR_DLL_NOTIFICATION_REASON_LOADED, got %x\n", calls);
3590
3591 calls = 0;
3592 FreeLibrary(mod);
3593 ok(calls == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Expected LDR_DLL_NOTIFICATION_REASON_UNLOADED, got %x\n", calls);
3594
3595 /* test order of callbacks */
3596 status = pLdrRegisterDllNotification(0, ldr_notify_callback2, &calls, &cookie2);
3597 ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3598
3599 calls = 0;
3600 mod = LoadLibraryW(ws2_32dllW);
3601 ok(!!mod, "Failed to load library: %d\n", GetLastError());
3602 ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
3603
3604 calls = 0;
3605 FreeLibrary(mod);
3606 ok(calls == 0x24, "Expected order 0x24, got %x\n", calls);
3607
3608 pLdrUnregisterDllNotification(cookie2);
3609 pLdrUnregisterDllNotification(cookie);
3610
3611 /* test dll main order */
3612 status = pLdrRegisterDllNotification(0, ldr_notify_callback_dll_main, &calls, &cookie);
3613 ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3614
3615 calls = 0;
3616 mod = LoadLibraryW(ws2_32dllW);
3617 ok(!!mod, "Failed to load library: %d\n", GetLastError());
3618 ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
3619
3620 calls = 0;
3621 FreeLibrary(mod);
3622 ok(calls == 0x42, "Expected order 0x42, got %x\n", calls);
3623
3624 pLdrUnregisterDllNotification(cookie);
3625
3626 /* test dll main order */
3627 status = pLdrRegisterDllNotification(0, ldr_notify_callback_fail, &calls, &cookie);
3628 ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3629
3630 calls = 0;
3631 mod = LoadLibraryW(ws2_32dllW);
3632 ok(!mod, "Expected library to fail loading\n");
3633 ok(calls == 0x1342, "Expected order 0x1342, got %x\n", calls);
3634
3635 pLdrUnregisterDllNotification(cookie);
3636
3637 /* test dll with dependencies */
3638 status = pLdrRegisterDllNotification(0, ldr_notify_callback_imports, &calls, &cookie);
3639 ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3640
3641 calls = 0;
3642 mod = LoadLibraryW(wintrustdllW);
3643 ok(!!mod, "Failed to load library: %d\n", GetLastError());
3644 ok(calls == 0x12, "Expected order 0x12, got %x\n", calls);
3645
3646 FreeLibrary(mod);
3647 pLdrUnregisterDllNotification(cookie);
3648 }
3649
3650 START_TEST(rtl)
3651 {
3652 InitFunctionPtrs();
3653
3654 test_RtlCompareMemory();
3655 test_RtlCompareMemoryUlong();
3656 test_RtlMoveMemory();
3657 test_RtlFillMemory();
3658 test_RtlFillMemoryUlong();
3659 test_RtlZeroMemory();
3660 test_RtlUlonglongByteSwap();
3661 test_RtlUniform();
3662 test_RtlRandom();
3663 test_RtlAreAllAccessesGranted();
3664 test_RtlAreAnyAccessesGranted();
3665 test_RtlComputeCrc32();
3666 test_HandleTables();
3667 test_RtlAllocateAndInitializeSid();
3668 test_RtlDeleteTimer();
3669 test_RtlThreadErrorMode();
3670 test_LdrProcessRelocationBlock();
3671 test_RtlIpv4AddressToString();
3672 test_RtlIpv4AddressToStringEx();
3673 test_RtlIpv4StringToAddress();
3674 test_RtlIpv4StringToAddressEx();
3675 test_RtlIpv6AddressToString();
3676 test_RtlIpv6AddressToStringEx();
3677 test_RtlIpv6StringToAddress();
3678 test_RtlIpv6StringToAddressEx();
3679 test_LdrAddRefDll();
3680 test_LdrLockLoaderLock();
3681 test_RtlCompressBuffer();
3682 test_RtlGetCompressionWorkSpaceSize();
3683 test_RtlDecompressBuffer();
3684 test_RtlIsCriticalSectionLocked();
3685 test_RtlInitializeCriticalSectionEx();
3686 test_RtlLeaveCriticalSection();
3687 test_LdrEnumerateLoadedModules();
3688 test_RtlQueryPackageIdentity();
3689 test_RtlMakeSelfRelativeSD();
3690 test_LdrRegisterDllNotification();
3691 }