[NTDLL_WINETEST] Sync with Wine Staging 1.7.43.
[reactos.git] / rostests / winetests / ntdll / rtl.c
1 /* Unit test suite for Rtl* API functions
2 *
3 * Copyright 2003 Thomas Mertes
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 * NOTES
20 * We use function pointers here as there is no import library for NTDLL on
21 * windows.
22 */
23
24 #include <stdlib.h>
25
26 #include "ntdll_test.h"
27 #include "inaddr.h"
28 #include "in6addr.h"
29
30 #ifndef __WINE_WINTERNL_H
31
32 typedef struct _RTL_HANDLE
33 {
34 struct _RTL_HANDLE * Next;
35 } RTL_HANDLE;
36
37 typedef struct _RTL_HANDLE_TABLE
38 {
39 ULONG MaxHandleCount;
40 ULONG HandleSize;
41 ULONG Unused[2];
42 PVOID NextFree;
43 PVOID FirstHandle;
44 PVOID ReservedMemory;
45 PVOID MaxHandle;
46 } RTL_HANDLE_TABLE;
47
48 #endif
49
50 /* avoid #include <winsock2.h> */
51 #undef htons
52 #ifdef WORDS_BIGENDIAN
53 #define htons(s) ((USHORT)(s))
54 #else /* WORDS_BIGENDIAN */
55 static inline USHORT __my_ushort_swap(USHORT s)
56 {
57 return (s >> 8) | (s << 8);
58 }
59 #define htons(s) __my_ushort_swap(s)
60 #endif /* WORDS_BIGENDIAN */
61
62
63
64 /* Function ptrs for ntdll calls */
65 static HMODULE hntdll = 0;
66 static PVOID (WINAPI *pWinSqmStartSession)(PVOID unknown1, DWORD unknown2, DWORD unknown3);
67 static BOOL (WINAPI *pWinSqmIsOptedIn)(void);
68 static NTSTATUS (WINAPI *pWinSqmEndSession)(PVOID unknown1);
69 static SIZE_T (WINAPI *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T);
70 static SIZE_T (WINAPI *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG);
71 static NTSTATUS (WINAPI *pRtlDeleteTimer)(HANDLE, HANDLE, HANDLE);
72 static VOID (WINAPI *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T);
73 static VOID (WINAPI *pRtlFillMemory)(LPVOID,SIZE_T,BYTE);
74 static VOID (WINAPI *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG);
75 static VOID (WINAPI *pRtlZeroMemory)(LPVOID,SIZE_T);
76 static ULONGLONG (WINAPIV *pRtlUlonglongByteSwap)(ULONGLONG source);
77 static ULONG (WINAPI *pRtlUniform)(PULONG);
78 static ULONG (WINAPI *pRtlRandom)(PULONG);
79 static BOOLEAN (WINAPI *pRtlAreAllAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
80 static BOOLEAN (WINAPI *pRtlAreAnyAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
81 static DWORD (WINAPI *pRtlComputeCrc32)(DWORD,const BYTE*,INT);
82 static void (WINAPI * pRtlInitializeHandleTable)(ULONG, ULONG, RTL_HANDLE_TABLE *);
83 static BOOLEAN (WINAPI * pRtlIsValidIndexHandle)(const RTL_HANDLE_TABLE *, ULONG, RTL_HANDLE **);
84 static NTSTATUS (WINAPI * pRtlDestroyHandleTable)(RTL_HANDLE_TABLE *);
85 static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *);
86 static BOOLEAN (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
87 static NTSTATUS (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
88 static NTSTATUS (WINAPI *pRtlFreeSid)(PSID);
89 static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
90 static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
91 static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
92 static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR);
93 static CHAR * (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR);
94 static NTSTATUS (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG);
95 static NTSTATUS (WINAPI *pRtlIpv4StringToAddressA)(PCSTR, BOOLEAN, PCSTR *, IN_ADDR *);
96 static NTSTATUS (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT);
97 static CHAR * (WINAPI *pRtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
98 static NTSTATUS (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG);
99 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressA)(PCSTR, PCSTR *, struct in6_addr *);
100 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressW)(PCWSTR, PCWSTR *, struct in6_addr *);
101 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExA)(PCSTR, struct in6_addr *, PULONG, PUSHORT);
102 static NTSTATUS (WINAPI *pRtlIpv6StringToAddressExW)(PCWSTR, struct in6_addr *, PULONG, PUSHORT);
103 static NTSTATUS (WINAPI *pLdrAddRefDll)(ULONG, HMODULE);
104 static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG*, ULONG_PTR*);
105 static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
106 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)(LPWSTR, DWORD, LPDWORD, LPCSTR, DWORD);
107 static NTSTATUS (WINAPI *pRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULONG);
108 static NTSTATUS (WINAPI *pRtlDecompressBuffer)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, PULONG);
109 static NTSTATUS (WINAPI *pRtlDecompressFragment)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, ULONG, PULONG, PVOID);
110 static NTSTATUS (WINAPI *pRtlCompressBuffer)(USHORT, const UCHAR*, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID);
111
112 static HMODULE hkernel32 = 0;
113 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
114
115
116 #define LEN 16
117 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
118 static ULONG src_aligned_block[4];
119 static ULONG dest_aligned_block[32];
120 static const char *src = (const char*)src_aligned_block;
121 static char* dest = (char*)dest_aligned_block;
122
123 static void InitFunctionPtrs(void)
124 {
125 hntdll = LoadLibraryA("ntdll.dll");
126 ok(hntdll != 0, "LoadLibrary failed\n");
127 if (hntdll) {
128 pWinSqmStartSession = (void *)GetProcAddress(hntdll, "WinSqmStartSession");
129 pWinSqmIsOptedIn = (void *)GetProcAddress(hntdll, "WinSqmIsOptedIn");
130 pWinSqmEndSession = (void *)GetProcAddress(hntdll, "WinSqmEndSession");
131 pRtlCompareMemory = (void *)GetProcAddress(hntdll, "RtlCompareMemory");
132 pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong");
133 pRtlDeleteTimer = (void *)GetProcAddress(hntdll, "RtlDeleteTimer");
134 pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory");
135 pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory");
136 pRtlFillMemoryUlong = (void *)GetProcAddress(hntdll, "RtlFillMemoryUlong");
137 pRtlZeroMemory = (void *)GetProcAddress(hntdll, "RtlZeroMemory");
138 pRtlUlonglongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlonglongByteSwap");
139 pRtlUniform = (void *)GetProcAddress(hntdll, "RtlUniform");
140 pRtlRandom = (void *)GetProcAddress(hntdll, "RtlRandom");
141 pRtlAreAllAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAllAccessesGranted");
142 pRtlAreAnyAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAnyAccessesGranted");
143 pRtlComputeCrc32 = (void *)GetProcAddress(hntdll, "RtlComputeCrc32");
144 pRtlInitializeHandleTable = (void *)GetProcAddress(hntdll, "RtlInitializeHandleTable");
145 pRtlIsValidIndexHandle = (void *)GetProcAddress(hntdll, "RtlIsValidIndexHandle");
146 pRtlDestroyHandleTable = (void *)GetProcAddress(hntdll, "RtlDestroyHandleTable");
147 pRtlAllocateHandle = (void *)GetProcAddress(hntdll, "RtlAllocateHandle");
148 pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
149 pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid");
150 pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid");
151 pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb");
152 pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode");
153 pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
154 pLdrProcessRelocationBlock = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock");
155 pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA");
156 pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA");
157 pRtlIpv4StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressA");
158 pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA");
159 pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA");
160 pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA");
161 pRtlIpv6StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressA");
162 pRtlIpv6StringToAddressW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressW");
163 pRtlIpv6StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExA");
164 pRtlIpv6StringToAddressExW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExW");
165 pLdrAddRefDll = (void *)GetProcAddress(hntdll, "LdrAddRefDll");
166 pLdrLockLoaderLock = (void *)GetProcAddress(hntdll, "LdrLockLoaderLock");
167 pLdrUnlockLoaderLock = (void *)GetProcAddress(hntdll, "LdrUnlockLoaderLock");
168 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll, "RtlMultiByteToUnicodeN");
169 pRtlGetCompressionWorkSpaceSize = (void *)GetProcAddress(hntdll, "RtlGetCompressionWorkSpaceSize");
170 pRtlDecompressBuffer = (void *)GetProcAddress(hntdll, "RtlDecompressBuffer");
171 pRtlDecompressFragment = (void *)GetProcAddress(hntdll, "RtlDecompressFragment");
172 pRtlCompressBuffer = (void *)GetProcAddress(hntdll, "RtlCompressBuffer");
173 }
174 hkernel32 = LoadLibraryA("kernel32.dll");
175 ok(hkernel32 != 0, "LoadLibrary failed\n");
176 if (hkernel32) {
177 pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
178 }
179 strcpy((char*)src_aligned_block, src_src);
180 ok(strlen(src) == 15, "Source must be 16 bytes long!\n");
181 }
182
183 #ifdef __i386__
184 const char stdcall3_thunk[] =
185 "\x56" /* push %esi */
186 "\x89\xE6" /* mov %esp, %esi */
187 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
188 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
189 "\xFF\x74\x24\x14" /* pushl 20(%esp) */
190 "\xFF\x54\x24\x14" /* calll 20(%esp) */
191 "\x89\xF0" /* mov %esi, %eax */
192 "\x29\xE0" /* sub %esp, %eax */
193 "\x89\xF4" /* mov %esi, %esp */
194 "\x5E" /* pop %esi */
195 "\xC2\x10\x00" /* ret $16 */
196 ;
197
198 static INT (WINAPI *call_stdcall_func3)(PVOID func, PVOID arg0, DWORD arg1, DWORD arg2) = NULL;
199
200 static void test_WinSqm(void)
201 {
202 INT args;
203
204 if (!pWinSqmStartSession)
205 {
206 win_skip("WinSqmStartSession() is not available\n");
207 return;
208 }
209
210 call_stdcall_func3 = (void*) VirtualAlloc( NULL, sizeof(stdcall3_thunk) - 1, MEM_COMMIT,
211 PAGE_EXECUTE_READWRITE );
212 memcpy( call_stdcall_func3, stdcall3_thunk, sizeof(stdcall3_thunk) - 1 );
213
214 args = 3 - call_stdcall_func3( pWinSqmStartSession, NULL, 0, 0 ) / 4;
215 ok(args == 3, "WinSqmStartSession expected to take %d arguments instead of 3\n", args);
216 args = 3 - call_stdcall_func3( pWinSqmIsOptedIn, NULL, 0, 0 ) / 4;
217 ok(args == 0, "WinSqmIsOptedIn expected to take %d arguments instead of 0\n", args);
218 args = 3 - call_stdcall_func3( pWinSqmEndSession, NULL, 0, 0 ) / 4;
219 ok(args == 1, "WinSqmEndSession expected to take %d arguments instead of 1\n", args);
220
221 VirtualFree( call_stdcall_func3, 0, MEM_RELEASE );
222 }
223 #endif
224
225 #define COMP(str1,str2,cmplen,len) size = pRtlCompareMemory(str1, str2, cmplen); \
226 ok(size == len, "Expected %ld, got %ld\n", size, (SIZE_T)len)
227
228 static void test_RtlCompareMemory(void)
229 {
230 SIZE_T size;
231
232 if (!pRtlCompareMemory)
233 {
234 win_skip("RtlCompareMemory is not available\n");
235 return;
236 }
237
238 strcpy(dest, src);
239
240 COMP(src,src,0,0);
241 COMP(src,src,LEN,LEN);
242 dest[0] = 'x';
243 COMP(src,dest,LEN,0);
244 }
245
246 static void test_RtlCompareMemoryUlong(void)
247 {
248 ULONG a[10];
249 ULONG result;
250
251 if (!pRtlCompareMemoryUlong)
252 {
253 win_skip("RtlCompareMemoryUlong is not available\n");
254 return;
255 }
256
257 a[0]= 0x0123;
258 a[1]= 0x4567;
259 a[2]= 0x89ab;
260 a[3]= 0xcdef;
261 result = pRtlCompareMemoryUlong(a, 0, 0x0123);
262 ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %u, expected 0\n", a, result);
263 result = pRtlCompareMemoryUlong(a, 3, 0x0123);
264 ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
265 result = pRtlCompareMemoryUlong(a, 4, 0x0123);
266 ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
267 result = pRtlCompareMemoryUlong(a, 5, 0x0123);
268 ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
269 result = pRtlCompareMemoryUlong(a, 7, 0x0123);
270 ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
271 result = pRtlCompareMemoryUlong(a, 8, 0x0123);
272 ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 4\n", a, result);
273 result = pRtlCompareMemoryUlong(a, 9, 0x0123);
274 ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 4\n", a, result);
275 result = pRtlCompareMemoryUlong(a, 4, 0x0127);
276 ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %u, expected 0\n", a, result);
277 result = pRtlCompareMemoryUlong(a, 4, 0x7123);
278 ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %u, expected 0\n", a, result);
279 result = pRtlCompareMemoryUlong(a, 16, 0x4567);
280 ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %u, expected 0\n", a, result);
281
282 a[1]= 0x0123;
283 result = pRtlCompareMemoryUlong(a, 3, 0x0123);
284 ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
285 result = pRtlCompareMemoryUlong(a, 4, 0x0123);
286 ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
287 result = pRtlCompareMemoryUlong(a, 5, 0x0123);
288 ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
289 result = pRtlCompareMemoryUlong(a, 7, 0x0123);
290 ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
291 result = pRtlCompareMemoryUlong(a, 8, 0x0123);
292 ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 8\n", a, result);
293 result = pRtlCompareMemoryUlong(a, 9, 0x0123);
294 ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 8\n", a, result);
295 }
296
297 #define COPY(len) memset(dest,0,sizeof(dest_aligned_block)); pRtlMoveMemory(dest, src, len)
298 #define CMP(str) ok(strcmp(dest,str) == 0, "Expected '%s', got '%s'\n", str, dest)
299
300 static void test_RtlMoveMemory(void)
301 {
302 if (!pRtlMoveMemory)
303 {
304 win_skip("RtlMoveMemory is not available\n");
305 return;
306 }
307
308 /* Length should be in bytes and not rounded. Use strcmp to ensure we
309 * didn't write past the end (it checks for the final NUL left by memset)
310 */
311 COPY(0); CMP("");
312 COPY(1); CMP("T");
313 COPY(2); CMP("Th");
314 COPY(3); CMP("Thi");
315 COPY(4); CMP("This");
316 COPY(5); CMP("This ");
317 COPY(6); CMP("This i");
318 COPY(7); CMP("This is");
319 COPY(8); CMP("This is ");
320 COPY(9); CMP("This is a");
321
322 /* Overlapping */
323 strcpy(dest, src); pRtlMoveMemory(dest, dest + 1, strlen(src) - 1);
324 CMP("his is a test!!");
325 strcpy(dest, src); pRtlMoveMemory(dest + 1, dest, strlen(src));
326 CMP("TThis is a test!");
327 }
328
329 #define FILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemory(dest,len,'x')
330
331 static void test_RtlFillMemory(void)
332 {
333 if (!pRtlFillMemory)
334 {
335 win_skip("RtlFillMemory is not available\n");
336 return;
337 }
338
339 /* Length should be in bytes and not rounded. Use strcmp to ensure we
340 * didn't write past the end (the remainder of the string should match)
341 */
342 FILL(0); CMP("This is a test!");
343 FILL(1); CMP("xhis is a test!");
344 FILL(2); CMP("xxis is a test!");
345 FILL(3); CMP("xxxs is a test!");
346 FILL(4); CMP("xxxx is a test!");
347 FILL(5); CMP("xxxxxis a test!");
348 FILL(6); CMP("xxxxxxs a test!");
349 FILL(7); CMP("xxxxxxx a test!");
350 FILL(8); CMP("xxxxxxxxa test!");
351 FILL(9); CMP("xxxxxxxxx test!");
352 }
353
354 #define LFILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemoryUlong(dest,len,val)
355
356 static void test_RtlFillMemoryUlong(void)
357 {
358 ULONG val = ('x' << 24) | ('x' << 16) | ('x' << 8) | 'x';
359 if (!pRtlFillMemoryUlong)
360 {
361 win_skip("RtlFillMemoryUlong is not available\n");
362 return;
363 }
364
365 /* Length should be in bytes and not rounded. Use strcmp to ensure we
366 * didn't write past the end (the remainder of the string should match)
367 */
368 LFILL(0); CMP("This is a test!");
369 LFILL(1); CMP("This is a test!");
370 LFILL(2); CMP("This is a test!");
371 LFILL(3); CMP("This is a test!");
372 LFILL(4); CMP("xxxx is a test!");
373 LFILL(5); CMP("xxxx is a test!");
374 LFILL(6); CMP("xxxx is a test!");
375 LFILL(7); CMP("xxxx is a test!");
376 LFILL(8); CMP("xxxxxxxxa test!");
377 LFILL(9); CMP("xxxxxxxxa test!");
378 }
379
380 #define ZERO(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlZeroMemory(dest,len)
381 #define MCMP(str) ok(memcmp(dest,str,LEN) == 0, "Memcmp failed\n")
382
383 static void test_RtlZeroMemory(void)
384 {
385 if (!pRtlZeroMemory)
386 {
387 win_skip("RtlZeroMemory is not available\n");
388 return;
389 }
390
391 /* Length should be in bytes and not rounded. */
392 ZERO(0); MCMP("This is a test!");
393 ZERO(1); MCMP("\0his is a test!");
394 ZERO(2); MCMP("\0\0is is a test!");
395 ZERO(3); MCMP("\0\0\0s is a test!");
396 ZERO(4); MCMP("\0\0\0\0 is a test!");
397 ZERO(5); MCMP("\0\0\0\0\0is a test!");
398 ZERO(6); MCMP("\0\0\0\0\0\0s a test!");
399 ZERO(7); MCMP("\0\0\0\0\0\0\0 a test!");
400 ZERO(8); MCMP("\0\0\0\0\0\0\0\0a test!");
401 ZERO(9); MCMP("\0\0\0\0\0\0\0\0\0 test!");
402 }
403
404 static void test_RtlUlonglongByteSwap(void)
405 {
406 ULONGLONG result;
407
408 if ( !pRtlUlonglongByteSwap )
409 {
410 win_skip("RtlUlonglongByteSwap is not available\n");
411 return;
412 }
413
414 if ( pRtlUlonglongByteSwap( 0 ) != 0 )
415 {
416 win_skip("Broken RtlUlonglongByteSwap in win2k\n");
417 return;
418 }
419
420 result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 );
421 ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result,
422 "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n",
423 (DWORD)(result >> 32), (DWORD)result);
424 }
425
426
427 static void test_RtlUniform(void)
428 {
429 ULONGLONG num;
430 ULONG seed;
431 ULONG seed_bak;
432 ULONG expected;
433 ULONG result;
434
435 if (!pRtlUniform)
436 {
437 win_skip("RtlUniform is not available\n");
438 return;
439 }
440
441 /*
442 * According to the documentation RtlUniform is using D.H. Lehmer's 1948
443 * algorithm. This algorithm is:
444 *
445 * seed = (seed * const_1 + const_2) % const_3;
446 *
447 * According to the documentation the random number is distributed over
448 * [0..MAXLONG]. Therefore const_3 is MAXLONG + 1:
449 *
450 * seed = (seed * const_1 + const_2) % (MAXLONG + 1);
451 *
452 * Because MAXLONG is 0x7fffffff (and MAXLONG + 1 is 0x80000000) the
453 * algorithm can be expressed without division as:
454 *
455 * seed = (seed * const_1 + const_2) & MAXLONG;
456 *
457 * To find out const_2 we just call RtlUniform with seed set to 0:
458 */
459 seed = 0;
460 expected = 0x7fffffc3;
461 result = pRtlUniform(&seed);
462 ok(result == expected,
463 "RtlUniform(&seed (seed == 0)) returns %x, expected %x\n",
464 result, expected);
465 /*
466 * The algorithm is now:
467 *
468 * seed = (seed * const_1 + 0x7fffffc3) & MAXLONG;
469 *
470 * To find out const_1 we can use:
471 *
472 * const_1 = RtlUniform(1) - 0x7fffffc3;
473 *
474 * If that does not work a search loop can try all possible values of
475 * const_1 and compare to the result to RtlUniform(1).
476 * This way we find out that const_1 is 0xffffffed.
477 *
478 * For seed = 1 the const_2 is 0x7fffffc4:
479 */
480 seed = 1;
481 expected = seed * 0xffffffed + 0x7fffffc3 + 1;
482 result = pRtlUniform(&seed);
483 ok(result == expected,
484 "RtlUniform(&seed (seed == 1)) returns %x, expected %x\n",
485 result, expected);
486 /*
487 * For seed = 2 the const_2 is 0x7fffffc3:
488 */
489 seed = 2;
490 expected = seed * 0xffffffed + 0x7fffffc3;
491 result = pRtlUniform(&seed);
492
493 /*
494 * Windows Vista uses different algorithms, so skip the rest of the tests
495 * until that is figured out. Trace output for the failures is about 10.5 MB!
496 */
497
498 if (result == 0x7fffff9f) {
499 skip("Most likely running on Windows Vista which uses a different algorithm\n");
500 return;
501 }
502
503 ok(result == expected,
504 "RtlUniform(&seed (seed == 2)) returns %x, expected %x\n",
505 result, expected);
506
507 /*
508 * More tests show that if seed is odd the result must be incremented by 1:
509 */
510 seed = 3;
511 expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1);
512 result = pRtlUniform(&seed);
513 ok(result == expected,
514 "RtlUniform(&seed (seed == 3)) returns %x, expected %x\n",
515 result, expected);
516
517 seed = 0x6bca1aa;
518 expected = seed * 0xffffffed + 0x7fffffc3;
519 result = pRtlUniform(&seed);
520 ok(result == expected,
521 "RtlUniform(&seed (seed == 0x6bca1aa)) returns %x, expected %x\n",
522 result, expected);
523
524 seed = 0x6bca1ab;
525 expected = seed * 0xffffffed + 0x7fffffc3 + 1;
526 result = pRtlUniform(&seed);
527 ok(result == expected,
528 "RtlUniform(&seed (seed == 0x6bca1ab)) returns %x, expected %x\n",
529 result, expected);
530 /*
531 * When seed is 0x6bca1ac there is an exception:
532 */
533 seed = 0x6bca1ac;
534 expected = seed * 0xffffffed + 0x7fffffc3 + 2;
535 result = pRtlUniform(&seed);
536 ok(result == expected,
537 "RtlUniform(&seed (seed == 0x6bca1ac)) returns %x, expected %x\n",
538 result, expected);
539 /*
540 * Note that up to here const_3 is not used
541 * (the highest bit of the result is not set).
542 *
543 * Starting with 0x6bca1ad: If seed is even the result must be incremented by 1:
544 */
545 seed = 0x6bca1ad;
546 expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG;
547 result = pRtlUniform(&seed);
548 ok(result == expected,
549 "RtlUniform(&seed (seed == 0x6bca1ad)) returns %x, expected %x\n",
550 result, expected);
551
552 seed = 0x6bca1ae;
553 expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG;
554 result = pRtlUniform(&seed);
555 ok(result == expected,
556 "RtlUniform(&seed (seed == 0x6bca1ae)) returns %x, expected %x\n",
557 result, expected);
558 /*
559 * There are several ranges where for odd or even seed the result must be
560 * incremented by 1. You can see this ranges in the following test.
561 *
562 * For a full test use one of the following loop heads:
563 *
564 * for (num = 0; num <= 0xffffffff; num++) {
565 * seed = num;
566 * ...
567 *
568 * seed = 0;
569 * for (num = 0; num <= 0xffffffff; num++) {
570 * ...
571 */
572 seed = 0;
573 for (num = 0; num <= 100000; num++) {
574
575 expected = seed * 0xffffffed + 0x7fffffc3;
576 if (seed < 0x6bca1ac) {
577 expected = expected + (seed & 1);
578 } else if (seed == 0x6bca1ac) {
579 expected = (expected + 2) & MAXLONG;
580 } else if (seed < 0xd79435c) {
581 expected = (expected + (~seed & 1)) & MAXLONG;
582 } else if (seed < 0x1435e50b) {
583 expected = expected + (seed & 1);
584 } else if (seed < 0x1af286ba) {
585 expected = (expected + (~seed & 1)) & MAXLONG;
586 } else if (seed < 0x21af2869) {
587 expected = expected + (seed & 1);
588 } else if (seed < 0x286bca18) {
589 expected = (expected + (~seed & 1)) & MAXLONG;
590 } else if (seed < 0x2f286bc7) {
591 expected = expected + (seed & 1);
592 } else if (seed < 0x35e50d77) {
593 expected = (expected + (~seed & 1)) & MAXLONG;
594 } else if (seed < 0x3ca1af26) {
595 expected = expected + (seed & 1);
596 } else if (seed < 0x435e50d5) {
597 expected = (expected + (~seed & 1)) & MAXLONG;
598 } else if (seed < 0x4a1af284) {
599 expected = expected + (seed & 1);
600 } else if (seed < 0x50d79433) {
601 expected = (expected + (~seed & 1)) & MAXLONG;
602 } else if (seed < 0x579435e2) {
603 expected = expected + (seed & 1);
604 } else if (seed < 0x5e50d792) {
605 expected = (expected + (~seed & 1)) & MAXLONG;
606 } else if (seed < 0x650d7941) {
607 expected = expected + (seed & 1);
608 } else if (seed < 0x6bca1af0) {
609 expected = (expected + (~seed & 1)) & MAXLONG;
610 } else if (seed < 0x7286bc9f) {
611 expected = expected + (seed & 1);
612 } else if (seed < 0x79435e4e) {
613 expected = (expected + (~seed & 1)) & MAXLONG;
614 } else if (seed < 0x7ffffffd) {
615 expected = expected + (seed & 1);
616 } else if (seed < 0x86bca1ac) {
617 expected = (expected + (~seed & 1)) & MAXLONG;
618 } else if (seed == 0x86bca1ac) {
619 expected = (expected + 1) & MAXLONG;
620 } else if (seed < 0x8d79435c) {
621 expected = expected + (seed & 1);
622 } else if (seed < 0x9435e50b) {
623 expected = (expected + (~seed & 1)) & MAXLONG;
624 } else if (seed < 0x9af286ba) {
625 expected = expected + (seed & 1);
626 } else if (seed < 0xa1af2869) {
627 expected = (expected + (~seed & 1)) & MAXLONG;
628 } else if (seed < 0xa86bca18) {
629 expected = expected + (seed & 1);
630 } else if (seed < 0xaf286bc7) {
631 expected = (expected + (~seed & 1)) & MAXLONG;
632 } else if (seed == 0xaf286bc7) {
633 expected = (expected + 2) & MAXLONG;
634 } else if (seed < 0xb5e50d77) {
635 expected = expected + (seed & 1);
636 } else if (seed < 0xbca1af26) {
637 expected = (expected + (~seed & 1)) & MAXLONG;
638 } else if (seed < 0xc35e50d5) {
639 expected = expected + (seed & 1);
640 } else if (seed < 0xca1af284) {
641 expected = (expected + (~seed & 1)) & MAXLONG;
642 } else if (seed < 0xd0d79433) {
643 expected = expected + (seed & 1);
644 } else if (seed < 0xd79435e2) {
645 expected = (expected + (~seed & 1)) & MAXLONG;
646 } else if (seed < 0xde50d792) {
647 expected = expected + (seed & 1);
648 } else if (seed < 0xe50d7941) {
649 expected = (expected + (~seed & 1)) & MAXLONG;
650 } else if (seed < 0xebca1af0) {
651 expected = expected + (seed & 1);
652 } else if (seed < 0xf286bc9f) {
653 expected = (expected + (~seed & 1)) & MAXLONG;
654 } else if (seed < 0xf9435e4e) {
655 expected = expected + (seed & 1);
656 } else if (seed < 0xfffffffd) {
657 expected = (expected + (~seed & 1)) & MAXLONG;
658 } else {
659 expected = expected + (seed & 1);
660 } /* if */
661 seed_bak = seed;
662 result = pRtlUniform(&seed);
663 ok(result == expected,
664 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
665 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
666 ok(seed == expected,
667 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
668 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
669 } /* for */
670 /*
671 * Further investigation shows: In the different regions the highest bit
672 * is set or cleared when even or odd seeds need an increment by 1.
673 * This leads to a simplified algorithm:
674 *
675 * seed = seed * 0xffffffed + 0x7fffffc3;
676 * if (seed == 0xffffffff || seed == 0x7ffffffe) {
677 * seed = (seed + 2) & MAXLONG;
678 * } else if (seed == 0x7fffffff) {
679 * seed = 0;
680 * } else if ((seed & 0x80000000) == 0) {
681 * seed = seed + (~seed & 1);
682 * } else {
683 * seed = (seed + (seed & 1)) & MAXLONG;
684 * }
685 *
686 * This is also the algorithm used for RtlUniform of wine (see dlls/ntdll/rtl.c).
687 *
688 * Now comes the funny part:
689 * It took me one weekend, to find the complicated algorithm and one day more,
690 * to find the simplified algorithm. Several weeks later I found out: The value
691 * MAXLONG (=0x7fffffff) is never returned, neither with the native function
692 * nor with the simplified algorithm. In reality the native function and our
693 * function return a random number distributed over [0..MAXLONG-1]. Note
694 * that this is different from what native documentation states [0..MAXLONG].
695 * Expressed with D.H. Lehmer's 1948 algorithm it looks like:
696 *
697 * seed = (seed * const_1 + const_2) % MAXLONG;
698 *
699 * Further investigations show that the real algorithm is:
700 *
701 * seed = (seed * 0x7fffffed + 0x7fffffc3) % MAXLONG;
702 *
703 * This is checked with the test below:
704 */
705 seed = 0;
706 for (num = 0; num <= 100000; num++) {
707 expected = (seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff;
708 seed_bak = seed;
709 result = pRtlUniform(&seed);
710 ok(result == expected,
711 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
712 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
713 ok(seed == expected,
714 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
715 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
716 } /* for */
717 /*
718 * More tests show that RtlUniform does not return 0x7ffffffd for seed values
719 * in the range [0..MAXLONG-1]. Additionally 2 is returned twice. This shows
720 * that there is more than one cycle of generated randon numbers ...
721 */
722 }
723
724
725 static ULONG my_RtlRandom(PULONG seed)
726 {
727 static ULONG saved_value[128] =
728 { /* 0 */ 0x4c8bc0aa, 0x4c022957, 0x2232827a, 0x2f1e7626, 0x7f8bdafb, 0x5c37d02a, 0x0ab48f72, 0x2f0c4ffa,
729 /* 8 */ 0x290e1954, 0x6b635f23, 0x5d3885c0, 0x74b49ff8, 0x5155fa54, 0x6214ad3f, 0x111e9c29, 0x242a3a09,
730 /* 16 */ 0x75932ae1, 0x40ac432e, 0x54f7ba7a, 0x585ccbd5, 0x6df5c727, 0x0374dad1, 0x7112b3f1, 0x735fc311,
731 /* 24 */ 0x404331a9, 0x74d97781, 0x64495118, 0x323e04be, 0x5974b425, 0x4862e393, 0x62389c1d, 0x28a68b82,
732 /* 32 */ 0x0f95da37, 0x7a50bbc6, 0x09b0091c, 0x22cdb7b4, 0x4faaed26, 0x66417ccd, 0x189e4bfa, 0x1ce4e8dd,
733 /* 40 */ 0x5274c742, 0x3bdcf4dc, 0x2d94e907, 0x32eac016, 0x26d33ca3, 0x60415a8a, 0x31f57880, 0x68c8aa52,
734 /* 48 */ 0x23eb16da, 0x6204f4a1, 0x373927c1, 0x0d24eb7c, 0x06dd7379, 0x2b3be507, 0x0f9c55b1, 0x2c7925eb,
735 /* 56 */ 0x36d67c9a, 0x42f831d9, 0x5e3961cb, 0x65d637a8, 0x24bb3820, 0x4d08e33d, 0x2188754f, 0x147e409e,
736 /* 64 */ 0x6a9620a0, 0x62e26657, 0x7bd8ce81, 0x11da0abb, 0x5f9e7b50, 0x23e444b6, 0x25920c78, 0x5fc894f0,
737 /* 72 */ 0x5e338cbb, 0x404237fd, 0x1d60f80f, 0x320a1743, 0x76013d2b, 0x070294ee, 0x695e243b, 0x56b177fd,
738 /* 80 */ 0x752492e1, 0x6decd52f, 0x125f5219, 0x139d2e78, 0x1898d11e, 0x2f7ee785, 0x4db405d8, 0x1a028a35,
739 /* 88 */ 0x63f6f323, 0x1f6d0078, 0x307cfd67, 0x3f32a78a, 0x6980796c, 0x462b3d83, 0x34b639f2, 0x53fce379,
740 /* 96 */ 0x74ba50f4, 0x1abc2c4b, 0x5eeaeb8d, 0x335a7a0d, 0x3973dd20, 0x0462d66b, 0x159813ff, 0x1e4643fd,
741 /* 104 */ 0x06bc5c62, 0x3115e3fc, 0x09101613, 0x47af2515, 0x4f11ec54, 0x78b99911, 0x3db8dd44, 0x1ec10b9b,
742 /* 112 */ 0x5b5506ca, 0x773ce092, 0x567be81a, 0x5475b975, 0x7a2cde1a, 0x494536f5, 0x34737bb4, 0x76d9750b,
743 /* 120 */ 0x2a1f6232, 0x2e49644d, 0x7dddcbe7, 0x500cebdb, 0x619dab9e, 0x48c626fe, 0x1cda3193, 0x52dabe9d };
744 ULONG rand;
745 int pos;
746 ULONG result;
747
748 rand = (*seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff;
749 *seed = (rand * 0x7fffffed + 0x7fffffc3) % 0x7fffffff;
750 pos = *seed & 0x7f;
751 result = saved_value[pos];
752 saved_value[pos] = rand;
753 return(result);
754 }
755
756
757 static void test_RtlRandom(void)
758 {
759 ULONGLONG num;
760 ULONG seed;
761 ULONG seed_bak;
762 ULONG seed_expected;
763 ULONG result;
764 ULONG result_expected;
765
766 if (!pRtlRandom)
767 {
768 win_skip("RtlRandom is not available\n");
769 return;
770 }
771
772 /*
773 * Unlike RtlUniform, RtlRandom is not documented. We guess that for
774 * RtlRandom D.H. Lehmer's 1948 algorithm is used like stated in
775 * the documentation of the RtlUniform function. This algorithm is:
776 *
777 * seed = (seed * const_1 + const_2) % const_3;
778 *
779 * According to the RtlUniform documentation the random number is
780 * distributed over [0..MAXLONG], but in reality it is distributed
781 * over [0..MAXLONG-1]. Therefore const_3 might be MAXLONG + 1 or
782 * MAXLONG:
783 *
784 * seed = (seed * const_1 + const_2) % (MAXLONG + 1);
785 *
786 * or
787 *
788 * seed = (seed * const_1 + const_2) % MAXLONG;
789 *
790 * To find out const_2 we just call RtlRandom with seed set to 0:
791 */
792 seed = 0;
793 result_expected = 0x320a1743;
794 seed_expected =0x44b;
795 result = pRtlRandom(&seed);
796
797 /*
798 * Windows Vista uses different algorithms, so skip the rest of the tests
799 * until that is figured out. Trace output for the failures is about 10.5 MB!
800 */
801
802 if (seed == 0x3fc) {
803 skip("Most likely running on Windows Vista which uses a different algorithm\n");
804 return;
805 }
806
807 ok(result == result_expected,
808 "pRtlRandom(&seed (seed == 0)) returns %x, expected %x\n",
809 result, result_expected);
810 ok(seed == seed_expected,
811 "pRtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n",
812 seed, seed_expected);
813 /*
814 * Seed is not equal to result as with RtlUniform. To see more we
815 * call RtlRandom again with seed set to 0:
816 */
817 seed = 0;
818 result_expected = 0x7fffffc3;
819 seed_expected =0x44b;
820 result = pRtlRandom(&seed);
821 ok(result == result_expected,
822 "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n",
823 result, result_expected);
824 ok(seed == seed_expected,
825 "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n",
826 seed, seed_expected);
827 /*
828 * Seed is set to the same value as before but the result is different.
829 * To see more we call RtlRandom again with seed set to 0:
830 */
831 seed = 0;
832 result_expected = 0x7fffffc3;
833 seed_expected =0x44b;
834 result = pRtlRandom(&seed);
835 ok(result == result_expected,
836 "RtlRandom(&seed (seed == 0)) returns %x, expected %x\n",
837 result, result_expected);
838 ok(seed == seed_expected,
839 "RtlRandom(&seed (seed == 0)) sets seed to %x, expected %x\n",
840 seed, seed_expected);
841 /*
842 * Seed is again set to the same value as before. This time we also
843 * have the same result as before. Interestingly the value of the
844 * result is 0x7fffffc3 which is the same value used in RtlUniform
845 * as const_2. If we do
846 *
847 * seed = 0;
848 * result = RtlUniform(&seed);
849 *
850 * we get the same result (0x7fffffc3) as with
851 *
852 * seed = 0;
853 * RtlRandom(&seed);
854 * seed = 0;
855 * result = RtlRandom(&seed);
856 *
857 * And there is another interesting thing. If we do
858 *
859 * seed = 0;
860 * RtlUniform(&seed);
861 * RtlUniform(&seed);
862 *
863 * seed is set to the value 0x44b which ist the same value that
864 *
865 * seed = 0;
866 * RtlRandom(&seed);
867 *
868 * assigns to seed. Putting these two findings together leads to
869 * the conclusion that RtlRandom saves the value in some variable,
870 * like in the following algorithm:
871 *
872 * result = saved_value;
873 * saved_value = RtlUniform(&seed);
874 * RtlUniform(&seed);
875 * return(result);
876 *
877 * Now we do further tests with seed set to 1:
878 */
879 seed = 1;
880 result_expected = 0x7a50bbc6;
881 seed_expected =0x5a1;
882 result = pRtlRandom(&seed);
883 ok(result == result_expected,
884 "RtlRandom(&seed (seed == 1)) returns %x, expected %x\n",
885 result, result_expected);
886 ok(seed == seed_expected,
887 "RtlRandom(&seed (seed == 1)) sets seed to %x, expected %x\n",
888 seed, seed_expected);
889 /*
890 * If there is just one saved_value the result now would be
891 * 0x7fffffc3. From this test we can see that there is more than
892 * one saved_value, like with this algorithm:
893 *
894 * result = saved_value[pos];
895 * saved_value[pos] = RtlUniform(&seed);
896 * RtlUniform(&seed);
897 * return(result);
898 *
899 * But how is the value of pos determined? The calls to RtlUniform
900 * create a sequence of random numbers. Every second random number
901 * is put into the saved_value array and is used in some later call
902 * of RtlRandom as result. The only reasonable source to determine
903 * pos are the random numbers generated by RtlUniform which are not
904 * put into the saved_value array. This are the values of seed
905 * between the two calls of RtlUniform as in this algorithm:
906 *
907 * rand = RtlUniform(&seed);
908 * RtlUniform(&seed);
909 * pos = position(seed);
910 * result = saved_value[pos];
911 * saved_value[pos] = rand;
912 * return(result);
913 *
914 * What remains to be determined is: The size of the saved_value array,
915 * the initial values of the saved_value array and the function
916 * position(seed). These tests are not shown here.
917 * The result of these tests is: The size of the saved_value array
918 * is 128, the initial values can be seen in the my_RtlRandom
919 * function and the position(seed) function is (seed & 0x7f).
920 *
921 * For a full test of RtlRandom use one of the following loop heads:
922 *
923 * for (num = 0; num <= 0xffffffff; num++) {
924 * seed = num;
925 * ...
926 *
927 * seed = 0;
928 * for (num = 0; num <= 0xffffffff; num++) {
929 * ...
930 */
931 seed = 0;
932 for (num = 0; num <= 100000; num++) {
933 seed_bak = seed;
934 seed_expected = seed;
935 result_expected = my_RtlRandom(&seed_expected);
936 /* The following corrections are necessary because the */
937 /* previous tests changed the saved_value array */
938 if (num == 0) {
939 result_expected = 0x7fffffc3;
940 } else if (num == 81) {
941 result_expected = 0x7fffffb1;
942 } /* if */
943 result = pRtlRandom(&seed);
944 ok(result == result_expected,
945 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
946 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, result_expected);
947 ok(seed == seed_expected,
948 "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
949 (DWORD)(num >> 32), (DWORD)num, seed_bak, result, seed_expected);
950 } /* for */
951 }
952
953
954 typedef struct {
955 ACCESS_MASK GrantedAccess;
956 ACCESS_MASK DesiredAccess;
957 BOOLEAN result;
958 } all_accesses_t;
959
960 static const all_accesses_t all_accesses[] = {
961 {0xFEDCBA76, 0xFEDCBA76, 1},
962 {0x00000000, 0xFEDCBA76, 0},
963 {0xFEDCBA76, 0x00000000, 1},
964 {0x00000000, 0x00000000, 1},
965 {0xFEDCBA76, 0xFEDCBA70, 1},
966 {0xFEDCBA70, 0xFEDCBA76, 0},
967 {0xFEDCBA76, 0xFEDC8A76, 1},
968 {0xFEDC8A76, 0xFEDCBA76, 0},
969 {0xFEDCBA76, 0xC8C4B242, 1},
970 {0xC8C4B242, 0xFEDCBA76, 0},
971 };
972 #define NB_ALL_ACCESSES (sizeof(all_accesses)/sizeof(*all_accesses))
973
974
975 static void test_RtlAreAllAccessesGranted(void)
976 {
977 unsigned int test_num;
978 BOOLEAN result;
979
980 if (!pRtlAreAllAccessesGranted)
981 {
982 win_skip("RtlAreAllAccessesGranted is not available\n");
983 return;
984 }
985
986 for (test_num = 0; test_num < NB_ALL_ACCESSES; test_num++) {
987 result = pRtlAreAllAccessesGranted(all_accesses[test_num].GrantedAccess,
988 all_accesses[test_num].DesiredAccess);
989 ok(all_accesses[test_num].result == result,
990 "(test %d): RtlAreAllAccessesGranted(%08x, %08x) returns %d, expected %d\n",
991 test_num, all_accesses[test_num].GrantedAccess,
992 all_accesses[test_num].DesiredAccess,
993 result, all_accesses[test_num].result);
994 } /* for */
995 }
996
997
998 typedef struct {
999 ACCESS_MASK GrantedAccess;
1000 ACCESS_MASK DesiredAccess;
1001 BOOLEAN result;
1002 } any_accesses_t;
1003
1004 static const any_accesses_t any_accesses[] = {
1005 {0xFEDCBA76, 0xFEDCBA76, 1},
1006 {0x00000000, 0xFEDCBA76, 0},
1007 {0xFEDCBA76, 0x00000000, 0},
1008 {0x00000000, 0x00000000, 0},
1009 {0xFEDCBA76, 0x01234589, 0},
1010 {0x00040000, 0xFEDCBA76, 1},
1011 {0x00040000, 0xFED8BA76, 0},
1012 {0xFEDCBA76, 0x00040000, 1},
1013 {0xFED8BA76, 0x00040000, 0},
1014 };
1015 #define NB_ANY_ACCESSES (sizeof(any_accesses)/sizeof(*any_accesses))
1016
1017
1018 static void test_RtlAreAnyAccessesGranted(void)
1019 {
1020 unsigned int test_num;
1021 BOOLEAN result;
1022
1023 if (!pRtlAreAnyAccessesGranted)
1024 {
1025 win_skip("RtlAreAnyAccessesGranted is not available\n");
1026 return;
1027 }
1028
1029 for (test_num = 0; test_num < NB_ANY_ACCESSES; test_num++) {
1030 result = pRtlAreAnyAccessesGranted(any_accesses[test_num].GrantedAccess,
1031 any_accesses[test_num].DesiredAccess);
1032 ok(any_accesses[test_num].result == result,
1033 "(test %d): RtlAreAnyAccessesGranted(%08x, %08x) returns %d, expected %d\n",
1034 test_num, any_accesses[test_num].GrantedAccess,
1035 any_accesses[test_num].DesiredAccess,
1036 result, any_accesses[test_num].result);
1037 } /* for */
1038 }
1039
1040 static void test_RtlComputeCrc32(void)
1041 {
1042 DWORD crc = 0;
1043
1044 if (!pRtlComputeCrc32)
1045 {
1046 win_skip("RtlComputeCrc32 is not available\n");
1047 return;
1048 }
1049
1050 crc = pRtlComputeCrc32(crc, (const BYTE *)src, LEN);
1051 ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8x\n", crc);
1052 }
1053
1054
1055 typedef struct MY_HANDLE
1056 {
1057 RTL_HANDLE RtlHandle;
1058 void * MyValue;
1059 } MY_HANDLE;
1060
1061 static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
1062 {
1063 ULONG_PTR *AllocatedBit = (ULONG_PTR *)(&Handle->Next);
1064 *AllocatedBit = *AllocatedBit | 1;
1065 }
1066
1067 static void test_HandleTables(void)
1068 {
1069 BOOLEAN result;
1070 NTSTATUS status;
1071 ULONG Index;
1072 MY_HANDLE * MyHandle;
1073 RTL_HANDLE_TABLE HandleTable;
1074
1075 if (!pRtlInitializeHandleTable)
1076 {
1077 win_skip("RtlInitializeHandleTable is not available\n");
1078 return;
1079 }
1080
1081 pRtlInitializeHandleTable(0x3FFF, sizeof(MY_HANDLE), &HandleTable);
1082 MyHandle = (MY_HANDLE *)pRtlAllocateHandle(&HandleTable, &Index);
1083 ok(MyHandle != NULL, "RtlAllocateHandle failed\n");
1084 RtlpMakeHandleAllocated(&MyHandle->RtlHandle);
1085 MyHandle = NULL;
1086 result = pRtlIsValidIndexHandle(&HandleTable, Index, (RTL_HANDLE **)&MyHandle);
1087 ok(result, "Handle %p wasn't valid\n", MyHandle);
1088 result = pRtlFreeHandle(&HandleTable, &MyHandle->RtlHandle);
1089 ok(result, "Couldn't free handle %p\n", MyHandle);
1090 status = pRtlDestroyHandleTable(&HandleTable);
1091 ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08x\n", status);
1092 }
1093
1094 static void test_RtlAllocateAndInitializeSid(void)
1095 {
1096 NTSTATUS ret;
1097 SID_IDENTIFIER_AUTHORITY sia = {{ 1, 2, 3, 4, 5, 6 }};
1098 PSID psid;
1099
1100 if (!pRtlAllocateAndInitializeSid)
1101 {
1102 win_skip("RtlAllocateAndInitializeSid is not available\n");
1103 return;
1104 }
1105
1106 ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
1107 ok(!ret, "RtlAllocateAndInitializeSid error %08x\n", ret);
1108 ret = pRtlFreeSid(psid);
1109 ok(!ret, "RtlFreeSid error %08x\n", ret);
1110
1111 /* these tests crash on XP */
1112 if (0)
1113 {
1114 pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
1115 pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL);
1116 }
1117
1118 ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
1119 ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret);
1120 }
1121
1122 static void test_RtlDeleteTimer(void)
1123 {
1124 NTSTATUS ret;
1125
1126 if (!pRtlDeleteTimer)
1127 {
1128 win_skip("RtlDeleteTimer is not available\n");
1129 return;
1130 }
1131
1132 ret = pRtlDeleteTimer(NULL, NULL, NULL);
1133 ok(ret == STATUS_INVALID_PARAMETER_1 ||
1134 ret == STATUS_INVALID_PARAMETER, /* W2K */
1135 "expected STATUS_INVALID_PARAMETER_1 or STATUS_INVALID_PARAMETER, got %x\n", ret);
1136 }
1137
1138 static void test_RtlThreadErrorMode(void)
1139 {
1140 DWORD oldmode;
1141 BOOL is_wow64;
1142 DWORD mode;
1143 NTSTATUS status;
1144
1145 if (!pRtlGetThreadErrorMode || !pRtlSetThreadErrorMode)
1146 {
1147 win_skip("RtlGetThreadErrorMode and/or RtlSetThreadErrorMode not available\n");
1148 return;
1149 }
1150
1151 if (!pIsWow64Process || !pIsWow64Process(GetCurrentProcess(), &is_wow64))
1152 is_wow64 = FALSE;
1153
1154 oldmode = pRtlGetThreadErrorMode();
1155
1156 status = pRtlSetThreadErrorMode(0x70, &mode);
1157 ok(status == STATUS_SUCCESS ||
1158 status == STATUS_WAIT_1, /* Vista */
1159 "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
1160 ok(mode == oldmode,
1161 "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
1162 mode, oldmode);
1163 ok(pRtlGetThreadErrorMode() == 0x70,
1164 "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70);
1165 if (!is_wow64 && pNtCurrentTeb)
1166 ok(pNtCurrentTeb()->HardErrorDisabled == 0x70,
1167 "The TEB contains 0x%x, expected 0x%x\n",
1168 pNtCurrentTeb()->HardErrorDisabled, 0x70);
1169
1170 status = pRtlSetThreadErrorMode(0, &mode);
1171 ok(status == STATUS_SUCCESS ||
1172 status == STATUS_WAIT_1, /* Vista */
1173 "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
1174 ok(mode == 0x70,
1175 "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
1176 mode, 0x70);
1177 ok(pRtlGetThreadErrorMode() == 0,
1178 "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0);
1179 if (!is_wow64 && pNtCurrentTeb)
1180 ok(pNtCurrentTeb()->HardErrorDisabled == 0,
1181 "The TEB contains 0x%x, expected 0x%x\n",
1182 pNtCurrentTeb()->HardErrorDisabled, 0);
1183
1184 for (mode = 1; mode; mode <<= 1)
1185 {
1186 status = pRtlSetThreadErrorMode(mode, NULL);
1187 if (mode & 0x70)
1188 ok(status == STATUS_SUCCESS ||
1189 status == STATUS_WAIT_1, /* Vista */
1190 "RtlSetThreadErrorMode(%x,NULL) failed with error 0x%08x\n",
1191 mode, status);
1192 else
1193 ok(status == STATUS_INVALID_PARAMETER_1,
1194 "RtlSetThreadErrorMode(%x,NULL) returns 0x%08x, "
1195 "expected STATUS_INVALID_PARAMETER_1\n",
1196 mode, status);
1197 }
1198
1199 pRtlSetThreadErrorMode(oldmode, NULL);
1200 }
1201
1202 static void test_LdrProcessRelocationBlock(void)
1203 {
1204 IMAGE_BASE_RELOCATION *ret;
1205 USHORT reloc;
1206 DWORD addr32;
1207 SHORT addr16;
1208
1209 if(!pLdrProcessRelocationBlock) {
1210 win_skip("LdrProcessRelocationBlock not available\n");
1211 return;
1212 }
1213
1214 addr32 = 0x50005;
1215 reloc = IMAGE_REL_BASED_HIGHLOW<<12;
1216 ret = pLdrProcessRelocationBlock(&addr32, 1, &reloc, 0x500050);
1217 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1218 ok(addr32 == 0x550055, "addr32 = %x, expected 0x550055\n", addr32);
1219
1220 addr16 = 0x505;
1221 reloc = IMAGE_REL_BASED_HIGH<<12;
1222 ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
1223 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1224 ok(addr16 == 0x555, "addr16 = %x, expected 0x555\n", addr16);
1225
1226 addr16 = 0x505;
1227 reloc = IMAGE_REL_BASED_LOW<<12;
1228 ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
1229 ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
1230 ok(addr16 == 0x565, "addr16 = %x, expected 0x565\n", addr16);
1231 }
1232
1233 static void test_RtlIpv4AddressToString(void)
1234 {
1235 CHAR buffer[20];
1236 CHAR *res;
1237 IN_ADDR ip;
1238 DWORD_PTR len;
1239
1240 if (!pRtlIpv4AddressToStringA)
1241 {
1242 win_skip("RtlIpv4AddressToStringA not available\n");
1243 return;
1244 }
1245
1246 ip.S_un.S_un_b.s_b1 = 1;
1247 ip.S_un.S_un_b.s_b2 = 2;
1248 ip.S_un.S_un_b.s_b3 = 3;
1249 ip.S_un.S_un_b.s_b4 = 4;
1250
1251 memset(buffer, '#', sizeof(buffer) - 1);
1252 buffer[sizeof(buffer) -1] = 0;
1253 res = pRtlIpv4AddressToStringA(&ip, buffer);
1254 len = strlen(buffer);
1255 ok(res == (buffer + len), "got %p with '%s' (expected %p)\n", res, buffer, buffer + len);
1256
1257 res = pRtlIpv4AddressToStringA(&ip, NULL);
1258 ok( (res == (char *)~0) ||
1259 broken(res == (char *)len), /* XP and w2003 */
1260 "got %p (expected ~0)\n", res);
1261
1262 if (0) {
1263 /* this crashes in windows */
1264 memset(buffer, '#', sizeof(buffer) - 1);
1265 buffer[sizeof(buffer) -1] = 0;
1266 res = pRtlIpv4AddressToStringA(NULL, buffer);
1267 trace("got %p with '%s'\n", res, buffer);
1268 }
1269
1270 if (0) {
1271 /* this crashes in windows */
1272 res = pRtlIpv4AddressToStringA(NULL, NULL);
1273 trace("got %p\n", res);
1274 }
1275 }
1276
1277 static void test_RtlIpv4AddressToStringEx(void)
1278 {
1279 CHAR ip_1234[] = "1.2.3.4";
1280 CHAR ip_1234_80[] = "1.2.3.4:80";
1281 LPSTR expect;
1282 CHAR buffer[30];
1283 NTSTATUS res;
1284 IN_ADDR ip;
1285 ULONG size;
1286 DWORD used;
1287 USHORT port;
1288
1289 if (!pRtlIpv4AddressToStringExA)
1290 {
1291 win_skip("RtlIpv4AddressToStringExA not available\n");
1292 return;
1293 }
1294
1295 ip.S_un.S_un_b.s_b1 = 1;
1296 ip.S_un.S_un_b.s_b2 = 2;
1297 ip.S_un.S_un_b.s_b3 = 3;
1298 ip.S_un.S_un_b.s_b4 = 4;
1299
1300 port = htons(80);
1301 expect = ip_1234_80;
1302
1303 size = sizeof(buffer);
1304 memset(buffer, '#', sizeof(buffer) - 1);
1305 buffer[sizeof(buffer) -1] = 0;
1306 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1307 used = strlen(buffer);
1308 ok( (res == STATUS_SUCCESS) &&
1309 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1310 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1311
1312 size = used + 1;
1313 memset(buffer, '#', sizeof(buffer) - 1);
1314 buffer[sizeof(buffer) -1] = 0;
1315 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1316 ok( (res == STATUS_SUCCESS) &&
1317 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1318 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1319
1320 size = used;
1321 memset(buffer, '#', sizeof(buffer) - 1);
1322 buffer[sizeof(buffer) -1] = 0;
1323 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1324 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1325 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1326 res, size, buffer, used + 1);
1327
1328 size = used - 1;
1329 memset(buffer, '#', sizeof(buffer) - 1);
1330 buffer[sizeof(buffer) -1] = 0;
1331 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1332 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1333 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1334 res, size, buffer, used + 1);
1335
1336
1337 /* to get only the ip, use 0 as port */
1338 port = 0;
1339 expect = ip_1234;
1340
1341 size = sizeof(buffer);
1342 memset(buffer, '#', sizeof(buffer) - 1);
1343 buffer[sizeof(buffer) -1] = 0;
1344 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1345 used = strlen(buffer);
1346 ok( (res == STATUS_SUCCESS) &&
1347 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1348 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1349
1350 size = used + 1;
1351 memset(buffer, '#', sizeof(buffer) - 1);
1352 buffer[sizeof(buffer) -1] = 0;
1353 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1354 ok( (res == STATUS_SUCCESS) &&
1355 (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1356 "got 0x%x and size %d with '%s'\n", res, size, buffer);
1357
1358 size = used;
1359 memset(buffer, '#', sizeof(buffer) - 1);
1360 buffer[sizeof(buffer) -1] = 0;
1361 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1362 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1363 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1364 res, size, buffer, used + 1);
1365
1366 size = used - 1;
1367 memset(buffer, '#', sizeof(buffer) - 1);
1368 buffer[sizeof(buffer) -1] = 0;
1369 res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1370 ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1371 "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1372 res, size, buffer, used + 1);
1373
1374
1375 /* parameters are checked */
1376 memset(buffer, '#', sizeof(buffer) - 1);
1377 buffer[sizeof(buffer) -1] = 0;
1378 res = pRtlIpv4AddressToStringExA(&ip, 0, buffer, NULL);
1379 ok(res == STATUS_INVALID_PARAMETER,
1380 "got 0x%x with '%s' (expected STATUS_INVALID_PARAMETER)\n", res, buffer);
1381
1382 size = sizeof(buffer);
1383 res = pRtlIpv4AddressToStringExA(&ip, 0, NULL, &size);
1384 ok( res == STATUS_INVALID_PARAMETER,
1385 "got 0x%x and size %d (expected STATUS_INVALID_PARAMETER)\n", res, size);
1386
1387 size = sizeof(buffer);
1388 memset(buffer, '#', sizeof(buffer) - 1);
1389 buffer[sizeof(buffer) -1] = 0;
1390 res = pRtlIpv4AddressToStringExA(NULL, 0, buffer, &size);
1391 ok( res == STATUS_INVALID_PARAMETER,
1392 "got 0x%x and size %d with '%s' (expected STATUS_INVALID_PARAMETER)\n",
1393 res, size, buffer);
1394 }
1395
1396 static struct
1397 {
1398 PCSTR address;
1399 NTSTATUS res;
1400 int terminator_offset;
1401 int ip[4];
1402 enum { normal_4, strict_diff_4 = 1, ex_fail_4 = 2 } flags;
1403 NTSTATUS res_strict;
1404 int terminator_offset_strict;
1405 int ip_strict[4];
1406 } ipv4_tests[] =
1407 {
1408 { "", STATUS_INVALID_PARAMETER, 0, { -1 } },
1409 { " ", STATUS_INVALID_PARAMETER, 0, { -1 } },
1410 { "1.1.1.1", STATUS_SUCCESS, 7, { 1, 1, 1, 1 } },
1411 { "0.0.0.0", STATUS_SUCCESS, 7, { 0, 0, 0, 0 } },
1412 { "255.255.255.255", STATUS_SUCCESS, 15, { 255, 255, 255, 255 } },
1413 { "255.255.255.255:123", STATUS_SUCCESS, 15, { 255, 255, 255, 255 } },
1414 { "255.255.255.256", STATUS_INVALID_PARAMETER, 15, { -1 } },
1415 { "255.255.255.4294967295", STATUS_INVALID_PARAMETER, 22, { -1 } },
1416 { "255.255.255.4294967296", STATUS_INVALID_PARAMETER, 21, { -1 } },
1417 { "255.255.255.4294967297", STATUS_INVALID_PARAMETER, 21, { -1 } },
1418 { "a", STATUS_INVALID_PARAMETER, 0, { -1 } },
1419 { "1.1.1.0xaA", STATUS_SUCCESS, 10, { 1, 1, 1, 170 }, strict_diff_4,
1420 STATUS_INVALID_PARAMETER, 8, { -1 } },
1421 { "1.1.1.0XaA", STATUS_SUCCESS, 10, { 1, 1, 1, 170 }, strict_diff_4,
1422 STATUS_INVALID_PARAMETER, 8, { -1 } },
1423 { "1.1.1.0x", STATUS_INVALID_PARAMETER, 8, { -1 } },
1424 { "1.1.1.0xff", STATUS_SUCCESS, 10, { 1, 1, 1, 255 }, strict_diff_4,
1425 STATUS_INVALID_PARAMETER, 8, { -1 } },
1426 { "1.1.1.0x100", STATUS_INVALID_PARAMETER, 11, { -1 }, strict_diff_4,
1427 STATUS_INVALID_PARAMETER, 8, { -1 } },
1428 { "1.1.1.0xffffffff", STATUS_INVALID_PARAMETER, 16, { -1 }, strict_diff_4,
1429 STATUS_INVALID_PARAMETER, 8, { -1 } },
1430 { "1.1.1.0x100000000", STATUS_INVALID_PARAMETER, 16, { -1, 0, 0, 0 }, strict_diff_4,
1431 STATUS_INVALID_PARAMETER, 8, { -1 } },
1432 { "1.1.1.010", STATUS_SUCCESS, 9, { 1, 1, 1, 8 }, strict_diff_4,
1433 STATUS_INVALID_PARAMETER, 7, { -1 } },
1434 { "1.1.1.00", STATUS_SUCCESS, 8, { 1, 1, 1, 0 }, strict_diff_4,
1435 STATUS_INVALID_PARAMETER, 7, { -1 } },
1436 { "1.1.1.007", STATUS_SUCCESS, 9, { 1, 1, 1, 7 }, strict_diff_4,
1437 STATUS_INVALID_PARAMETER, 7, { -1 } },
1438 { "1.1.1.08", STATUS_INVALID_PARAMETER, 7, { -1 } },
1439 { "1.1.1.008", STATUS_SUCCESS, 8, { 1, 1, 1, 0 }, strict_diff_4 | ex_fail_4,
1440 STATUS_INVALID_PARAMETER, 7, { -1 } },
1441 { "1.1.1.0a", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1442 { "1.1.1.0o10", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1443 { "1.1.1.0b10", STATUS_SUCCESS, 7, { 1, 1, 1, 0 }, ex_fail_4 },
1444 { "1.1.1.-2", STATUS_INVALID_PARAMETER, 6, { -1 } },
1445 { "1", STATUS_SUCCESS, 1, { 0, 0, 0, 1 }, strict_diff_4,
1446 STATUS_INVALID_PARAMETER, 1, { -1 } },
1447 { "-1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1448 { "203569230", STATUS_SUCCESS, 9, { 12, 34, 56, 78 }, strict_diff_4,
1449 STATUS_INVALID_PARAMETER, 9, { -1 } },
1450 { "1.223756", STATUS_SUCCESS, 8, { 1, 3, 106, 12 }, strict_diff_4,
1451 STATUS_INVALID_PARAMETER, 8, { -1 } },
1452 { "3.4.756", STATUS_SUCCESS, 7, { 3, 4, 2, 244 }, strict_diff_4,
1453 STATUS_INVALID_PARAMETER, 7, { -1 } },
1454 { "3.4.756.1", STATUS_INVALID_PARAMETER, 9, { -1 } },
1455 { "3.4.65536", STATUS_INVALID_PARAMETER, 9, { -1 } },
1456 { "3.4.5.6.7", STATUS_INVALID_PARAMETER, 7, { -1 } },
1457 { "3.4.5.+6", STATUS_INVALID_PARAMETER, 6, { -1 } },
1458 { " 3.4.5.6", STATUS_INVALID_PARAMETER, 0, { -1 } },
1459 { "\t3.4.5.6", STATUS_INVALID_PARAMETER, 0, { -1 } },
1460 { "3.4.5.6 ", STATUS_SUCCESS, 7, { 3, 4, 5, 6 }, ex_fail_4 },
1461 { "3. 4.5.6", STATUS_INVALID_PARAMETER, 2, { -1 } },
1462 { ".", STATUS_INVALID_PARAMETER, 1, { -1 } },
1463 { "..", STATUS_INVALID_PARAMETER, 1, { -1 } },
1464 { "1.", STATUS_INVALID_PARAMETER, 2, { -1 } },
1465 { "1..", STATUS_INVALID_PARAMETER, 3, { -1 } },
1466 { ".1", STATUS_INVALID_PARAMETER, 1, { -1 } },
1467 { ".1.", STATUS_INVALID_PARAMETER, 1, { -1 } },
1468 { ".1.2.3", STATUS_INVALID_PARAMETER, 1, { -1 } },
1469 { "0.1.2.3", STATUS_SUCCESS, 7, { 0, 1, 2, 3 } },
1470 { "0.1.2.3.", STATUS_INVALID_PARAMETER, 7, { -1 } },
1471 { "[0.1.2.3]", STATUS_INVALID_PARAMETER, 0, { -1 } },
1472 { "::1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1473 { ":1", STATUS_INVALID_PARAMETER, 0, { -1 } },
1474 };
1475 const unsigned int ipv4_testcount = sizeof(ipv4_tests) / sizeof(ipv4_tests[0]);
1476
1477 static void init_ip4(IN_ADDR* addr, const int src[4])
1478 {
1479 if (!src || src[0] == -1)
1480 {
1481 addr->S_un.S_addr = 0xabababab;
1482 }
1483 else
1484 {
1485 addr->S_un.S_un_b.s_b1 = src[0];
1486 addr->S_un.S_un_b.s_b2 = src[1];
1487 addr->S_un.S_un_b.s_b3 = src[2];
1488 addr->S_un.S_un_b.s_b4 = src[3];
1489 }
1490 }
1491
1492 static void test_RtlIpv4StringToAddress(void)
1493 {
1494 NTSTATUS res;
1495 IN_ADDR ip, expected_ip;
1496 PCSTR terminator;
1497 CHAR dummy;
1498 unsigned int i;
1499
1500 if (!pRtlIpv4StringToAddressA)
1501 {
1502 skip("RtlIpv4StringToAddress not available\n");
1503 return;
1504 }
1505
1506 if (0)
1507 {
1508 /* leaving either parameter NULL crashes on Windows */
1509 res = pRtlIpv4StringToAddressA(NULL, FALSE, &terminator, &ip);
1510 res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, NULL, &ip);
1511 res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, &terminator, NULL);
1512 /* same for the wide char version */
1513 /*
1514 res = pRtlIpv4StringToAddressW(NULL, FALSE, &terminatorW, &ip);
1515 res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, NULL, &ip);
1516 res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, &terminatorW, NULL);
1517 */
1518 }
1519
1520 for (i = 0; i < ipv4_testcount; i++)
1521 {
1522 /* non-strict */
1523 terminator = &dummy;
1524 ip.S_un.S_addr = 0xabababab;
1525 res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, FALSE, &terminator, &ip);
1526 ok(res == ipv4_tests[i].res,
1527 "[%s] res = 0x%08x, expected 0x%08x\n",
1528 ipv4_tests[i].address, res, ipv4_tests[i].res);
1529 ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset,
1530 "[%s] terminator = %p, expected %p\n",
1531 ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset);
1532
1533 init_ip4(&expected_ip, ipv4_tests[i].ip);
1534 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1535 "[%s] ip = %08x, expected %08x\n",
1536 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1537
1538 if (!(ipv4_tests[i].flags & strict_diff_4))
1539 {
1540 ipv4_tests[i].res_strict = ipv4_tests[i].res;
1541 ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1542 ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1543 ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1544 ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1545 ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1546 }
1547 /* strict */
1548 terminator = &dummy;
1549 ip.S_un.S_addr = 0xabababab;
1550 res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, TRUE, &terminator, &ip);
1551 ok(res == ipv4_tests[i].res_strict,
1552 "[%s] res = 0x%08x, expected 0x%08x\n",
1553 ipv4_tests[i].address, res, ipv4_tests[i].res_strict);
1554 ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict,
1555 "[%s] terminator = %p, expected %p\n",
1556 ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict);
1557
1558 init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1559 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1560 "[%s] ip = %08x, expected %08x\n",
1561 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1562 }
1563 }
1564
1565 static void test_RtlIpv4StringToAddressEx(void)
1566 {
1567 NTSTATUS res;
1568 IN_ADDR ip, expected_ip;
1569 USHORT port;
1570 static const struct
1571 {
1572 PCSTR address;
1573 NTSTATUS res;
1574 int ip[4];
1575 USHORT port;
1576 } ipv4_ex_tests[] =
1577 {
1578 { "", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1579 { " ", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1580 { "1.1.1.1:", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
1581 { "1.1.1.1+", STATUS_INVALID_PARAMETER, { 1, 1, 1, 1 }, 0xdead },
1582 { "1.1.1.1:1", STATUS_SUCCESS, { 1, 1, 1, 1 }, 0x100 },
1583 { "256.1.1.1:1", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1584 { "-1.1.1.1:1", STATUS_INVALID_PARAMETER, { -1 }, 0xdead },
1585 { "0.0.0.0:0", STATUS_INVALID_PARAMETER, { 0, 0, 0, 0 }, 0xdead },
1586 { "0.0.0.0:1", STATUS_SUCCESS, { 0, 0, 0, 0 }, 0x100 },
1587 { "1.2.3.4:65535", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1588 { "1.2.3.4:65536", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1589 { "1.2.3.4:0xffff", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1590 { "1.2.3.4:0XfFfF", STATUS_SUCCESS, { 1, 2, 3, 4 }, 65535 },
1591 { "1.2.3.4:011064", STATUS_SUCCESS, { 1, 2, 3, 4 }, 0x3412 },
1592 { "1.2.3.4:1234a", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1593 { "1.2.3.4:1234+", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1594 { "1.2.3.4: 1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1595 { "1.2.3.4:\t1234", STATUS_INVALID_PARAMETER, { 1, 2, 3, 4 }, 0xdead },
1596 };
1597 const unsigned int ipv4_ex_testcount = sizeof(ipv4_ex_tests) / sizeof(ipv4_ex_tests[0]);
1598 unsigned int i;
1599 BOOLEAN strict;
1600
1601 if (!pRtlIpv4StringToAddressExA)
1602 {
1603 skip("RtlIpv4StringToAddressEx not available\n");
1604 return;
1605 }
1606
1607 /* do not crash, and do not touch the ip / port. */
1608 ip.S_un.S_addr = 0xabababab;
1609 port = 0xdead;
1610 res = pRtlIpv4StringToAddressExA(NULL, FALSE, &ip, &port);
1611 ok(res == STATUS_INVALID_PARAMETER, "[null address] res = 0x%08x, expected 0x%08x\n",
1612 res, STATUS_INVALID_PARAMETER);
1613 ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1614 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1615
1616 port = 0xdead;
1617 res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, NULL, &port);
1618 ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected 0x%08x\n",
1619 res, STATUS_INVALID_PARAMETER);
1620 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1621
1622 ip.S_un.S_addr = 0xabababab;
1623 port = 0xdead;
1624 res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, &ip, NULL);
1625 ok(res == STATUS_INVALID_PARAMETER, "[null port] res = 0x%08x, expected 0x%08x\n",
1626 res, STATUS_INVALID_PARAMETER);
1627 ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1628 ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1629
1630 /* first we run the non-ex testcases on the ex function */
1631 for (i = 0; i < ipv4_testcount; i++)
1632 {
1633 NTSTATUS expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res;
1634
1635 /* non-strict */
1636 port = 0xdead;
1637 ip.S_un.S_addr = 0xabababab;
1638 res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, FALSE, &ip, &port);
1639 ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1640 ipv4_tests[i].address, res, expect_res);
1641
1642 init_ip4(&expected_ip, ipv4_tests[i].ip);
1643 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1644 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1645
1646 if (!(ipv4_tests[i].flags & strict_diff_4))
1647 {
1648 ipv4_tests[i].res_strict = ipv4_tests[i].res;
1649 ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1650 ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1651 ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1652 ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1653 ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1654 }
1655 /* strict */
1656 expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res_strict;
1657 port = 0xdead;
1658 ip.S_un.S_addr = 0xabababab;
1659 res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, TRUE, &ip, &port);
1660 ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1661 ipv4_tests[i].address, res, expect_res);
1662
1663 init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1664 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1665 ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1666 }
1667
1668
1669 for (i = 0; i < ipv4_ex_testcount; i++)
1670 {
1671 /* Strict is only relevant for the ip address, so make sure that it does not influence the port */
1672 for (strict = 0; strict < 2; strict++)
1673 {
1674 ip.S_un.S_addr = 0xabababab;
1675 port = 0xdead;
1676 res = pRtlIpv4StringToAddressExA(ipv4_ex_tests[i].address, strict, &ip, &port);
1677 ok(res == ipv4_ex_tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
1678 ipv4_ex_tests[i].address, res, ipv4_ex_tests[i].res);
1679
1680 init_ip4(&expected_ip, ipv4_ex_tests[i].ip);
1681 ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1682 ipv4_ex_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1683 ok(port == ipv4_ex_tests[i].port, "[%s] port = %u, expected %u\n",
1684 ipv4_ex_tests[i].address, port, ipv4_ex_tests[i].port);
1685 }
1686 }
1687 }
1688
1689 /* ipv6 addresses based on the set from https://github.com/beaugunderson/javascript-ipv6/tree/master/test/data */
1690 static const struct
1691 {
1692 PCSTR address;
1693 NTSTATUS res;
1694 int terminator_offset;
1695 int ip[8];
1696 /* win_broken: older versions of windows do not handle this correct
1697 ex_fail: Ex function does need the string to be terminated, non-Ex does not.
1698 ex_skip: test doesnt make sense for Ex (f.e. it's invalid for non-Ex but valid for Ex) */
1699 enum { normal_6, win_broken_6 = 1, ex_fail_6 = 2, ex_skip_6 = 4 } flags;
1700 } ipv6_tests[] =
1701 {
1702 { "0000:0000:0000:0000:0000:0000:0000:0000", STATUS_SUCCESS, 39,
1703 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1704 { "0000:0000:0000:0000:0000:0000:0000:0001", STATUS_SUCCESS, 39,
1705 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1706 { "0:0:0:0:0:0:0:0", STATUS_SUCCESS, 15,
1707 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1708 { "0:0:0:0:0:0:0:1", STATUS_SUCCESS, 15,
1709 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1710 { "0:0:0:0:0:0:0::", STATUS_SUCCESS, 13,
1711 { 0, 0, 0, 0, 0, 0, 0, 0 }, win_broken_6 },
1712 { "0:0:0:0:0:0:13.1.68.3", STATUS_SUCCESS, 21,
1713 { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1714 { "0:0:0:0:0:0::", STATUS_SUCCESS, 13,
1715 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1716 { "0:0:0:0:0::", STATUS_SUCCESS, 11,
1717 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1718 { "0:0:0:0:0:FFFF:129.144.52.38", STATUS_SUCCESS, 28,
1719 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
1720 { "0::", STATUS_SUCCESS, 3,
1721 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1722 { "0:1:2:3:4:5:6:7", STATUS_SUCCESS, 15,
1723 { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
1724 { "1080:0:0:0:8:800:200c:417a", STATUS_SUCCESS, 26,
1725 { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
1726 { "0:a:b:c:d:e:f::", STATUS_SUCCESS, 13,
1727 { 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0 }, win_broken_6 },
1728 { "1111:2222:3333:4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 45,
1729 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1730 { "1111:2222:3333:4444:5555:6666:7777:8888", STATUS_SUCCESS, 39,
1731 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1732 { "1111:2222:3333:4444:0x5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 21,
1733 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1734 { "1111:2222:3333:4444:x555:6666:7777:8888", STATUS_INVALID_PARAMETER, 20,
1735 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1736 { "1111:2222:3333:4444:0r5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 21,
1737 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1738 { "1111:2222:3333:4444:r5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 20,
1739 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1740 { "1111:2222:3333:4444:5555:6666:7777::", STATUS_SUCCESS, 34,
1741 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0 }, win_broken_6 },
1742 { "1111:2222:3333:4444:5555:6666::", STATUS_SUCCESS, 31,
1743 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
1744 { "1111:2222:3333:4444:5555:6666::8888", STATUS_SUCCESS, 35,
1745 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
1746 { "1111:2222:3333:4444:5555::", STATUS_SUCCESS, 26,
1747 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
1748 { "1111:2222:3333:4444:5555::123.123.123.123", STATUS_SUCCESS, 41,
1749 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
1750 { "1111:2222:3333:4444:5555::0x1.123.123.123", STATUS_SUCCESS, 27,
1751 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x100 }, ex_fail_6 },
1752 { "1111:2222:3333:4444:5555::0x88", STATUS_SUCCESS, 27,
1753 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1754 { "1111:2222:3333:4444:5555::0X88", STATUS_SUCCESS, 27,
1755 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1756 { "1111:2222:3333:4444:5555::0X", STATUS_SUCCESS, 27,
1757 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 }, ex_fail_6 },
1758 { "1111:2222:3333:4444:5555::0X88:7777", STATUS_SUCCESS, 27,
1759 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1760 { "1111:2222:3333:4444:5555::0x8888", STATUS_SUCCESS, 27,
1761 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 }, ex_fail_6 },
1762 { "1111:2222:3333:4444:5555::08888", STATUS_INVALID_PARAMETER, 31,
1763 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1764 { "1111:2222:3333:4444:5555::fffff", STATUS_INVALID_PARAMETER, 31,
1765 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1766 { "1111:2222:3333:4444::fffff", STATUS_INVALID_PARAMETER, 26,
1767 { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1768 { "1111:2222:3333::fffff", STATUS_INVALID_PARAMETER, 21,
1769 { 0x1111, 0x2222, 0x3333, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1770 { "1111:2222:3333:4444:5555::7777:8888", STATUS_SUCCESS, 35,
1771 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
1772 { "1111:2222:3333:4444:5555::8888", STATUS_SUCCESS, 30,
1773 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
1774 { "1111::", STATUS_SUCCESS, 6,
1775 { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1776 { "1111::123.123.123.123", STATUS_SUCCESS, 21,
1777 { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1778 { "1111::3333:4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 41,
1779 { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1780 { "1111::3333:4444:5555:6666:7777:8888", STATUS_SUCCESS, 35,
1781 { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1782 { "1111::4444:5555:6666:123.123.123.123", STATUS_SUCCESS, 36,
1783 { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1784 { "1111::4444:5555:6666:7777:8888", STATUS_SUCCESS, 30,
1785 { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1786 { "1111::5555:6666:123.123.123.123", STATUS_SUCCESS, 31,
1787 { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1788 { "1111::5555:6666:7777:8888", STATUS_SUCCESS, 25,
1789 { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
1790 { "1111::6666:123.123.123.123", STATUS_SUCCESS, 26,
1791 { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
1792 { "1111::6666:7777:8888", STATUS_SUCCESS, 20,
1793 { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
1794 { "1111::7777:8888", STATUS_SUCCESS, 15,
1795 { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
1796 { "1111::8888", STATUS_SUCCESS, 10,
1797 { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
1798 { "1:2:3:4:5:6:1.2.3.4", STATUS_SUCCESS, 19,
1799 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
1800 { "1:2:3:4:5:6:7:8", STATUS_SUCCESS, 15,
1801 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
1802 { "1:2:3:4:5:6::", STATUS_SUCCESS, 13,
1803 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
1804 { "1:2:3:4:5:6::8", STATUS_SUCCESS, 14,
1805 { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
1806 { "2001:0000:1234:0000:0000:C1C0:ABCD:0876", STATUS_SUCCESS, 39,
1807 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1808 { "2001:0000:4136:e378:8000:63bf:3fff:fdd2", STATUS_SUCCESS, 39,
1809 { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
1810 { "2001:0db8:0:0:0:0:1428:57ab", STATUS_SUCCESS, 27,
1811 { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
1812 { "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff", STATUS_SUCCESS, 39,
1813 { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1814 { "2001::CE49:7601:2CAD:DFFF:7C94:FFFE", STATUS_SUCCESS, 35,
1815 { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
1816 { "2001:db8:85a3::8a2e:370:7334", STATUS_SUCCESS, 28,
1817 { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
1818 { "3ffe:0b00:0000:0000:0001:0000:0000:000a", STATUS_SUCCESS, 39,
1819 { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
1820 { "::", STATUS_SUCCESS, 2,
1821 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1822 { "::%16", STATUS_SUCCESS, 2,
1823 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1824 { "::/16", STATUS_SUCCESS, 2,
1825 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1826 { "::0", STATUS_SUCCESS, 3,
1827 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1828 { "::0:0", STATUS_SUCCESS, 5,
1829 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1830 { "::0:0:0", STATUS_SUCCESS, 7,
1831 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1832 { "::0:0:0:0", STATUS_SUCCESS, 9,
1833 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1834 { "::0:0:0:0:0", STATUS_SUCCESS, 11,
1835 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1836 { "::0:0:0:0:0:0", STATUS_SUCCESS, 13,
1837 { 0, 0, 0, 0, 0, 0, 0, 0 } },
1838 /* this one and the next one are incorrectly parsed by windows,
1839 it adds one zero too many in front, cutting off the last digit. */
1840 { "::0:0:0:0:0:0:0", STATUS_SUCCESS, 13,
1841 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1842 { "::0:a:b:c:d:e:f", STATUS_SUCCESS, 13,
1843 { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 }, ex_fail_6 },
1844 { "::123.123.123.123", STATUS_SUCCESS, 17,
1845 { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1846 { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", STATUS_SUCCESS, 39,
1847 { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1848
1849 { "':10.0.0.1", STATUS_INVALID_PARAMETER, 0,
1850 { -1 } },
1851 { "-1", STATUS_INVALID_PARAMETER, 0,
1852 { -1 } },
1853 { "02001:0000:1234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1854 { -1 } },
1855 { "2001:00000:1234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1856 { 0x120, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1857 { "2001:0000:01234:0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, -1,
1858 { 0x120, 0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1859 { "1.2.3.4", STATUS_INVALID_PARAMETER, 7,
1860 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1861 { "1.2.3.4:1111::5555", STATUS_INVALID_PARAMETER, 7,
1862 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1863 { "1.2.3.4::5555", STATUS_INVALID_PARAMETER, 7,
1864 { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1865 { "11112222:3333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, -1,
1866 { -1 } },
1867 { "11112222:3333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, -1,
1868 { -1 } },
1869 { "1111", STATUS_INVALID_PARAMETER, 4,
1870 { -1 } },
1871 { "1111:22223333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, -1,
1872 { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1873 { "1111:22223333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, -1,
1874 { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1875 { "1111:2222:", STATUS_INVALID_PARAMETER, 10,
1876 { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1877 { "1111:2222:1.2.3.4", STATUS_INVALID_PARAMETER, 17,
1878 { 0x1111, 0x2222, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab } },
1879 { "1111:2222:3333", STATUS_INVALID_PARAMETER, 14,
1880 { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1881 { "1111:2222:3333:4444:5555:6666:7777:1.2.3.4", STATUS_SUCCESS, 36,
1882 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 }, ex_fail_6 },
1883 { "1111:2222:3333:4444:5555:6666:7777:8888:", STATUS_SUCCESS, 39,
1884 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1885 { "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",STATUS_SUCCESS, 39,
1886 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1887 { "1111:2222:3333:4444:5555:6666:7777:8888:9999", STATUS_SUCCESS, 39,
1888 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1889 { "1111:2222:::", STATUS_SUCCESS, 11,
1890 { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1891 { "1111::5555:", STATUS_INVALID_PARAMETER, 11,
1892 { 0x1111, 0x5555, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1893 { "1111::3333:4444:5555:6666:7777::", STATUS_SUCCESS, 30,
1894 { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 }, ex_fail_6 },
1895 { "1111:2222:::4444:5555:6666:1.2.3.4", STATUS_SUCCESS, 11,
1896 { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1897 { "1111::3333::5555:6666:1.2.3.4", STATUS_SUCCESS, 10,
1898 { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 }, ex_fail_6 },
1899 { "12345::6:7:8", STATUS_INVALID_PARAMETER, -1,
1900 { -1 } },
1901 { "1::1.2.256.4", STATUS_INVALID_PARAMETER, -1,
1902 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1903 { "1::1.2.3.256", STATUS_INVALID_PARAMETER, 12,
1904 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1905 { "1::1.2.3.300", STATUS_INVALID_PARAMETER, 12,
1906 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1907 { "1::1.2::1", STATUS_INVALID_PARAMETER, 6,
1908 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1909 { "1::1.2.3.4::1", STATUS_SUCCESS, 10,
1910 { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 }, ex_fail_6 },
1911 { "1::1.", STATUS_INVALID_PARAMETER, 5,
1912 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1913 { "1::1.2", STATUS_INVALID_PARAMETER, 6,
1914 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1915 { "1::1.2.", STATUS_INVALID_PARAMETER, 7,
1916 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1917 { "1::1.2.3", STATUS_INVALID_PARAMETER, 8,
1918 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1919 { "1::1.2.3.", STATUS_INVALID_PARAMETER, 9,
1920 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1921 { "1::1.2.3.4", STATUS_SUCCESS, 10,
1922 { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 } },
1923 { "1::1.2.3.900", STATUS_INVALID_PARAMETER, 12,
1924 { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1925 { "1::1.2.300.4", STATUS_INVALID_PARAMETER, -1,
1926 { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1927 { "1::1.256.3.4", STATUS_INVALID_PARAMETER, -1,
1928 { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1929 { "1::256.2.3.4", STATUS_INVALID_PARAMETER, -1,
1930 { 0x100, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1931 { "1::2::3", STATUS_SUCCESS, 4,
1932 { 0x100, 0, 0, 0, 0, 0, 0, 0x200 }, ex_fail_6 },
1933 { "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", STATUS_INVALID_PARAMETER, 15,
1934 { 0x120, 0, 0x3412, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1935 { "2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", STATUS_SUCCESS, 39,
1936 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 }, ex_fail_6 },
1937 { "2001:1:1:1:1:1:255Z255X255Y255", STATUS_INVALID_PARAMETER, 18,
1938 { 0x120, 0x100, 0x100, 0x100, 0x100, 0x100, 0xabab, 0xabab } },
1939 { "2001::FFD3::57ab", STATUS_SUCCESS, 10,
1940 { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff }, ex_fail_6 },
1941 { ":", STATUS_INVALID_PARAMETER, 0,
1942 { -1 } },
1943 { ":1111:2222:3333:4444:5555:6666:1.2.3.4", STATUS_INVALID_PARAMETER, 0,
1944 { -1 } },
1945 { ":1111:2222:3333:4444:5555:6666:7777:8888", STATUS_INVALID_PARAMETER, 0,
1946 { -1 } },
1947 { ":1111::", STATUS_INVALID_PARAMETER, 0,
1948 { -1 } },
1949 { "::-1", STATUS_SUCCESS, 2,
1950 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1951 { "::.", STATUS_SUCCESS, 2,
1952 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1953 { "::..", STATUS_SUCCESS, 2,
1954 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1955 { "::...", STATUS_SUCCESS, 2,
1956 { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1957 { "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4", STATUS_INVALID_PARAMETER, 0,
1958 { -1 } },
1959 { "[::]", STATUS_INVALID_PARAMETER, 0,
1960 { -1 }, ex_skip_6 },
1961 };
1962 const unsigned int ipv6_testcount = sizeof(ipv6_tests) / sizeof(ipv6_tests[0]);
1963
1964 static void init_ip6(IN6_ADDR* addr, const int src[8])
1965 {
1966 unsigned int j;
1967 if (!src || src[0] == -1)
1968 {
1969 for (j = 0; j < 8; ++j)
1970 addr->s6_words[j] = 0xabab;
1971 }
1972 else
1973 {
1974 for (j = 0; j < 8; ++j)
1975 addr->s6_words[j] = src[j];
1976 }
1977 }
1978
1979 static void test_RtlIpv6AddressToString(void)
1980 {
1981 CHAR buffer[50];
1982 LPCSTR result;
1983 IN6_ADDR ip;
1984 DWORD_PTR len;
1985 struct
1986 {
1987 PCSTR address;
1988 int ip[8];
1989 } tests[] =
1990 {
1991 /* ipv4 addresses & ISATAP addresses */
1992 { "::13.1.68.3", { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1993 { "::ffff:13.1.68.3", { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0x344 } },
1994 { "::feff:d01:4403", { 0, 0, 0, 0, 0, 0xfffe, 0x10d, 0x344 } },
1995 { "::fffe:d01:4403", { 0, 0, 0, 0, 0, 0xfeff, 0x10d, 0x344 } },
1996 { "::100:d01:4403", { 0, 0, 0, 0, 0, 1, 0x10d, 0x344 } },
1997 { "::1:d01:4403", { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1998 { "::ffff:0:4403", { 0, 0, 0, 0, 0, 0xffff, 0, 0x344 } },
1999 { "::ffff:13.1.0.0", { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0 } },
2000 { "::ffff:0:0", { 0, 0, 0, 0, 0, 0xffff, 0, 0 } },
2001 { "::ffff:0:13.1.68.3", { 0, 0, 0, 0, 0xffff, 0, 0x10d, 0x344 } },
2002 { "::ffff:ffff:d01:4403", { 0, 0, 0, 0, 0xffff, 0xffff, 0x10d, 0x344 } },
2003 { "::ffff:0:0:d01:4403", { 0, 0, 0, 0xffff, 0, 0, 0x10d, 0x344 } },
2004 { "::ffff:255.255.255.255", { 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff } },
2005 { "::ffff:129.144.52.38", { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2006 { "::5efe:129.144.52.38", { 0, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
2007 { "1111:2222:3333:4444:0:5efe:129.144.52.38", { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2008 { "1111:2222:3333::5efe:129.144.52.38", { 0x1111, 0x2222, 0x3333, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
2009 { "1111:2222::5efe:129.144.52.38", { 0x1111, 0x2222, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
2010 { "1111::5efe:129.144.52.38", { 0x1111, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
2011 { "::200:5efe:129.144.52.38", { 0, 0, 0, 0, 2, 0xfe5e, 0x9081, 0x2634 } },
2012 { "::100:5efe:8190:3426", { 0, 0, 0, 0, 1, 0xfe5e, 0x9081, 0x2634 } },
2013 /* 'normal' addresses */
2014 { "::1", { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2015 { "0:1:2:3:4:5:6:7", { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
2016 { "1080::8:800:200c:417a", { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
2017 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2018 { "1111:2222:3333:4444:5555:6666:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
2019 { "1111:2222:3333:4444:5555:6666::", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
2020 { "1111:2222:3333:4444:5555:6666:0:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
2021 { "1111:2222:3333:4444:5555::", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
2022 { "1111:2222:3333:4444:5555:0:7b7b:7b7b", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
2023 { "1111:2222:3333:4444:5555:0:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
2024 { "1111:2222:3333:4444:5555::8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
2025 { "1111::", { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2026 { "1111::7b7b:7b7b", { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
2027 { "1111:0:3333:4444:5555:6666:7b7b:7b7b", { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2028 { "1111:0:3333:4444:5555:6666:7777:8888", { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
2029 { "1111::4444:5555:6666:7b7b:7b7b", { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2030 { "1111::4444:5555:6666:7777:8888", { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
2031 { "1111::5555:6666:7b7b:7b7b", { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2032 { "1111::5555:6666:7777:8888", { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
2033 { "1111::6666:7b7b:7b7b", { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
2034 { "1111::6666:7777:8888", { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
2035 { "1111::7777:8888", { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
2036 { "1111::8888", { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
2037 { "1:2:3:4:5:6:102:304", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
2038 { "1:2:3:4:5:6:7:8", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
2039 { "1:2:3:4:5:6::", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
2040 { "1:2:3:4:5:6:0:8", { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
2041 { "2001:0:1234::c1c0:abcd:876", { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
2042 { "2001:0:4136:e378:8000:63bf:3fff:fdd2", { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
2043 { "2001:db8::1428:57ab", { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
2044 { "2001:db8:1234:ffff:ffff:ffff:ffff:ffff", { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
2045 { "2001:0:ce49:7601:2cad:dfff:7c94:fffe", { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
2046 { "2001:db8:85a3::8a2e:370:7334", { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
2047 { "3ffe:b00::1:0:0:a", { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
2048 { "::a:b:c:d:e", { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 } },
2049 { "::123.123.123.123", { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
2050 { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
2051 { "1111:2222:3333:4444:5555:6666:7777:1", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 } },
2052 { "1111:2222:3333:4444:5555:6666:7777:8888", { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
2053 { "1111:2222::", { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
2054 { "1111::3333:4444:5555:6666:7777", { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 } },
2055 { "1111:2222::", { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
2056 { "1111::3333", { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 } },
2057 { "2001:0:1234::c1c0:abcd:876", { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
2058 { "2001::ffd3", { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2059 };
2060 const size_t testcount = sizeof(tests) / sizeof(tests[0]);
2061 unsigned int i;
2062
2063 if (!pRtlIpv6AddressToStringA)
2064 {
2065 skip("RtlIpv6AddressToStringA not available\n");
2066 return;
2067 }
2068
2069 memset(buffer, '#', sizeof(buffer));
2070 buffer[sizeof(buffer)-1] = 0;
2071 memset(&ip, 0, sizeof(ip));
2072 result = pRtlIpv6AddressToStringA(&ip, buffer);
2073
2074 len = strlen(buffer);
2075 ok(result == (buffer + len) && !strcmp(buffer, "::"),
2076 "got %p with '%s' (expected %p with '::')\n", result, buffer, buffer + len);
2077
2078 result = pRtlIpv6AddressToStringA(&ip, NULL);
2079 ok(result == (LPCSTR)~0 || broken(result == (LPCSTR)len) /* WinXP / Win2k3 */,
2080 "got %p, expected %p\n", result, (LPCSTR)~0);
2081
2082 for (i = 0; i < testcount; i++)
2083 {
2084 init_ip6(&ip, tests[i].ip);
2085 memset(buffer, '#', sizeof(buffer));
2086 buffer[sizeof(buffer)-1] = 0;
2087
2088 result = pRtlIpv6AddressToStringA(&ip, buffer);
2089 len = strlen(buffer);
2090 ok(result == (buffer + len) && !strcmp(buffer, tests[i].address),
2091 "got %p with '%s' (expected %p with '%s')\n", result, buffer, buffer + len, tests[i].address);
2092
2093 ok(buffer[45] == 0 || broken(buffer[45] != 0) /* WinXP / Win2k3 */,
2094 "expected data at buffer[45] to always be NULL\n");
2095 ok(buffer[46] == '#', "expected data at buffer[46] not to change\n");
2096 }
2097 }
2098
2099 static void test_RtlIpv6AddressToStringEx(void)
2100 {
2101 CHAR buffer[70];
2102 NTSTATUS res;
2103 IN6_ADDR ip;
2104 ULONG len;
2105 struct
2106 {
2107 PCSTR address;
2108 ULONG scopeid;
2109 USHORT port;
2110 int ip[8];
2111 } tests[] =
2112 {
2113 /* ipv4 addresses & ISATAP addresses */
2114 { "::13.1.68.3", 0, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2115 { "::13.1.68.3%1", 1, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2116 { "::13.1.68.3%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2117 { "[::13.1.68.3%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2118 { "[::13.1.68.3%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2119 { "[::13.1.68.3]:256", 0, 1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
2120
2121 { "::1:d01:4403", 0, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2122 { "::1:d01:4403%1", 1, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2123 { "::1:d01:4403%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2124 { "[::1:d01:4403%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2125 { "[::1:d01:4403%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2126 { "[::1:d01:4403]:256", 0, 1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
2127
2128 { "1111:2222:3333:4444:0:5efe:129.144.52.38", 0, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2129 { "1111:2222:3333:4444:0:5efe:129.144.52.38%1", 1, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2130 { "1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819", 0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2131 { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:65518",0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2132 { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2133 { "[1111:2222:3333:4444:0:5efe:129.144.52.38]:256", 0, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
2134
2135 { "::1", 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2136 { "::1%1", 1, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2137 { "::1%4294949819", 0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2138 { "[::1%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2139 { "[::1%4294949819]:256", 0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2140 { "[::1]:256", 0, 1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2141
2142 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b", 0, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2143 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%1", 1, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2144 { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819", 0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2145 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2146 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2147 { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b]:256", 0, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
2148
2149 { "1111::", 0, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2150 { "1111::%1", 1, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2151 { "1111::%4294949819", 0xffffbbbb, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2152 { "[1111::%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2153 { "[1111::%4294949819]:256", 0xffffbbbb, 1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2154 { "[1111::]:256", 0, 1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
2155
2156 { "2001::ffd3", 0, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2157 { "2001::ffd3%1", 1, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2158 { "2001::ffd3%4294949819", 0xffffbbbb, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2159 { "[2001::ffd3%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2160 { "[2001::ffd3%4294949819]:256", 0xffffbbbb, 1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2161 { "[2001::ffd3]:256", 0, 1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
2162 };
2163 const size_t testcount = sizeof(tests) / sizeof(tests[0]);
2164 unsigned int i;
2165
2166 if (!pRtlIpv6AddressToStringExA)
2167 {
2168 skip("RtlIpv6AddressToStringExA not available\n");
2169 return;
2170 }
2171
2172 memset(buffer, '#', sizeof(buffer));
2173 buffer[sizeof(buffer)-1] = 0;
2174 memset(&ip, 0, sizeof(ip));
2175 len = sizeof(buffer);
2176 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
2177
2178 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2179 ok(len == 3 && !strcmp(buffer, "::"),
2180 "got len %d with '%s' (expected 3 with '::')\n", len, buffer);
2181
2182 memset(buffer, '#', sizeof(buffer));
2183 buffer[sizeof(buffer)-1] = 0;
2184
2185 len = sizeof(buffer);
2186 res = pRtlIpv6AddressToStringExA(NULL, 0, 0, buffer, &len);
2187 ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2188
2189 len = sizeof(buffer);
2190 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, NULL, &len);
2191 ok(res == STATUS_INVALID_PARAMETER, "[null buffer] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2192
2193 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, NULL);
2194 ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2195
2196 len = 2;
2197 memset(buffer, '#', sizeof(buffer));
2198 buffer[sizeof(buffer)-1] = 0;
2199 res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
2200 ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2201 ok(buffer[0] == '#', "got first char %c (expected '#')\n", buffer[0]);
2202 ok(len == 3, "got len %d (expected len 3)\n", len);
2203
2204 for (i = 0; i < testcount; i++)
2205 {
2206 init_ip6(&ip, tests[i].ip);
2207 len = sizeof(buffer);
2208 memset(buffer, '#', sizeof(buffer));
2209 buffer[sizeof(buffer)-1] = 0;
2210
2211 res = pRtlIpv6AddressToStringExA(&ip, tests[i].scopeid, tests[i].port, buffer, &len);
2212
2213 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2214 ok(len == (strlen(tests[i].address) + 1) && !strcmp(buffer, tests[i].address),
2215 "got len %d with '%s' (expected %d with '%s')\n", len, buffer, strlen(tests[i].address), tests[i].address);
2216 }
2217 }
2218
2219 static void compare_RtlIpv6StringToAddressW(PCSTR name_a, int terminator_offset_a,
2220 const struct in6_addr *addr_a, NTSTATUS res_a)
2221 {
2222 WCHAR name[512];
2223 NTSTATUS res;
2224 IN6_ADDR ip;
2225 PCWSTR terminator;
2226
2227 if (!pRtlIpv6StringToAddressW)
2228 return;
2229
2230 pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
2231
2232 init_ip6(&ip, NULL);
2233 terminator = (void *)0xdeadbeef;
2234 res = pRtlIpv6StringToAddressW(name, &terminator, &ip);
2235 ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2236
2237 if (terminator_offset_a < 0)
2238 {
2239 ok(terminator == (void *)0xdeadbeef,
2240 "[W:%s] terminator = %p, expected it not to change\n",
2241 name_a, terminator);
2242 }
2243 else
2244 {
2245 ok(terminator == name + terminator_offset_a,
2246 "[W:%s] terminator = %p, expected %p\n",
2247 name_a, terminator, name + terminator_offset_a);
2248 }
2249
2250 ok(!memcmp(&ip, addr_a, sizeof(ip)),
2251 "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2252 name_a,
2253 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2254 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2255 addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2256 addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2257 }
2258
2259 static void test_RtlIpv6StringToAddress(void)
2260 {
2261 NTSTATUS res;
2262 IN6_ADDR ip, expected_ip;
2263 PCSTR terminator;
2264 unsigned int i;
2265
2266 if (!pRtlIpv6StringToAddressW)
2267 {
2268 skip("RtlIpv6StringToAddressW not available\n");
2269 /* we can continue, just not test W */
2270 }
2271
2272 if (!pRtlIpv6StringToAddressA)
2273 {
2274 skip("RtlIpv6StringToAddressA not available\n");
2275 return; /* all tests are centered around A, we cannot continue */
2276 }
2277
2278 res = pRtlIpv6StringToAddressA("::", &terminator, &ip);
2279 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2280 if (0)
2281 {
2282 /* any of these crash */
2283 res = pRtlIpv6StringToAddressA(NULL, &terminator, &ip);
2284 ok(res == STATUS_INVALID_PARAMETER, "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2285 res = pRtlIpv6StringToAddressA("::", NULL, &ip);
2286 ok(res == STATUS_INVALID_PARAMETER, "[null terminator] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2287 res = pRtlIpv6StringToAddressA("::", &terminator, NULL);
2288 ok(res == STATUS_INVALID_PARAMETER, "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2289 }
2290
2291 /* sanity check */
2292 ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2293
2294 for (i = 0; i < ipv6_testcount; i++)
2295 {
2296 init_ip6(&ip, NULL);
2297 terminator = (void *)0xdeadbeef;
2298 res = pRtlIpv6StringToAddressA(ipv6_tests[i].address, &terminator, &ip);
2299 compare_RtlIpv6StringToAddressW(ipv6_tests[i].address, (terminator != (void *)0xdeadbeef) ?
2300 (terminator - ipv6_tests[i].address) : -1, &ip, res);
2301
2302 if (ipv6_tests[i].flags & win_broken_6)
2303 {
2304 ok(res == ipv6_tests[i].res || broken(res == STATUS_INVALID_PARAMETER),
2305 "[%s] res = 0x%08x, expected 0x%08x\n",
2306 ipv6_tests[i].address, res, ipv6_tests[i].res);
2307
2308 if (res == STATUS_INVALID_PARAMETER)
2309 continue;
2310 }
2311 else
2312 {
2313 ok(res == ipv6_tests[i].res,
2314 "[%s] res = 0x%08x, expected 0x%08x\n",
2315 ipv6_tests[i].address, res, ipv6_tests[i].res);
2316 }
2317
2318 if (ipv6_tests[i].terminator_offset < 0)
2319 {
2320 ok(terminator == (void *)0xdeadbeef,
2321 "[%s] terminator = %p, expected it not to change\n",
2322 ipv6_tests[i].address, terminator);
2323 }
2324 else if (ipv6_tests[i].flags & win_broken_6)
2325 {
2326 PCSTR expected = ipv6_tests[i].address + ipv6_tests[i].terminator_offset;
2327 ok(terminator == expected || broken(terminator == expected + 2),
2328 "[%s] terminator = %p, expected %p\n",
2329 ipv6_tests[i].address, terminator, expected);
2330 }
2331 else
2332 {
2333 ok(terminator == ipv6_tests[i].address + ipv6_tests[i].terminator_offset,
2334 "[%s] terminator = %p, expected %p\n",
2335 ipv6_tests[i].address, terminator, ipv6_tests[i].address + ipv6_tests[i].terminator_offset);
2336 }
2337
2338 init_ip6(&expected_ip, ipv6_tests[i].ip);
2339 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2340 "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2341 ipv6_tests[i].address,
2342 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2343 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2344 expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2345 expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2346 }
2347 }
2348
2349 static void compare_RtlIpv6StringToAddressExW(PCSTR name_a, const struct in6_addr *addr_a, HRESULT res_a, ULONG scope_a, USHORT port_a)
2350 {
2351 WCHAR name[512];
2352 NTSTATUS res;
2353 IN6_ADDR ip;
2354 ULONG scope = 0xbadf00d;
2355 USHORT port = 0xbeef;
2356
2357 if (!pRtlIpv6StringToAddressExW)
2358 return;
2359
2360 pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
2361
2362 init_ip6(&ip, NULL);
2363 res = pRtlIpv6StringToAddressExW(name, &ip, &scope, &port);
2364
2365 ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2366 ok(scope == scope_a, "[W:%s] scope = 0x%08x, expected 0x%08x\n", name_a, scope, scope_a);
2367 ok(port == port_a, "[W:%s] port = 0x%08x, expected 0x%08x\n", name_a, port, port_a);
2368
2369 ok(!memcmp(&ip, addr_a, sizeof(ip)),
2370 "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2371 name_a,
2372 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2373 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2374 addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2375 addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2376 }
2377
2378 static void test_RtlIpv6StringToAddressEx(void)
2379 {
2380 NTSTATUS res;
2381 IN6_ADDR ip, expected_ip;
2382 ULONG scope;
2383 USHORT port;
2384 static const struct
2385 {
2386 PCSTR address;
2387 NTSTATUS res;
2388 ULONG scope;
2389 USHORT port;
2390 int ip[8];
2391 } ipv6_ex_tests[] =
2392 {
2393 { "[::]", STATUS_SUCCESS, 0, 0,
2394 { 0, 0, 0, 0, 0, 0, 0, 0 } },
2395 { "[::1]:8080", STATUS_SUCCESS, 0, 0x901f,
2396 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2397 { "[::1]:0x80", STATUS_SUCCESS, 0, 0x8000,
2398 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2399 { "[::1]:0X80", STATUS_SUCCESS, 0, 0x8000,
2400 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2401 { "[::1]:080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2402 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2403 { "[::1]:800000000080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2404 { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2405 { "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80", STATUS_SUCCESS, 0, 0x5000,
2406 { 0xdcfe, 0x98ba, 0x5476, 0x1032, 0xdcfe, 0x98ba, 0x5476, 0x1032 } },
2407 { "[1080:0:0:0:8:800:200C:417A]:1234", STATUS_SUCCESS, 0, 0xd204,
2408 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2409 { "[3ffe:2a00:100:7031::1]:8080", STATUS_SUCCESS, 0, 0x901f,
2410 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2411 { "[ 3ffe:2a00:100:7031::1]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2412 { -1 } },
2413 { "[3ffe:2a00:100:7031::1 ]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2414 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2415 { "[3ffe:2a00:100:7031::1].8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2416 { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2417 { "[1080::8:800:200C:417A]:8080", STATUS_SUCCESS, 0, 0x901f,
2418 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2419 { "[1080::8:800:200C:417A]!8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2420 { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2421 { "[::FFFF:129.144.52.38]:80", STATUS_SUCCESS, 0, 0x5000,
2422 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2423 { "[::FFFF:129.144.52.38]:-80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2424 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2425 { "[::FFFF:129.144.52.38]:999999999999", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2426 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2427 { "[::FFFF:129.144.52.38%-8]:80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2428 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2429 { "[::FFFF:129.144.52.38]:80", STATUS_SUCCESS, 0, 0x5000,
2430 { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2431 { "[12345::6:7:8]:80", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2432 { -1 } },
2433 { "[ff01::8:800:200C:417A%16]:8080", STATUS_SUCCESS, 16, 0x901f,
2434 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2435 { "[ff01::8:800:200C:417A%100]:8080", STATUS_SUCCESS, 100, 0x901f,
2436 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2437 { "[ff01::8:800:200C:417A%1000]:8080", STATUS_SUCCESS, 1000, 0x901f,
2438 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2439 { "[ff01::8:800:200C:417A%10000]:8080", STATUS_SUCCESS, 10000, 0x901f,
2440 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2441 { "[ff01::8:800:200C:417A%1000000]:8080", STATUS_SUCCESS, 1000000, 0x901f,
2442 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2443 { "[ff01::8:800:200C:417A%4294967295]:8080", STATUS_SUCCESS, 0xffffffff, 0x901f,
2444 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2445 { "[ff01::8:800:200C:417A%4294967296]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2446 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2447 { "[ff01::8:800:200C:417A%-1]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2448 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2449 { "[ff01::8:800:200C:417A%0]:8080", STATUS_SUCCESS, 0, 0x901f,
2450 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2451 { "[ff01::8:800:200C:417A%1", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2452 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2453 { "[ff01::8:800:200C:417A%0x1000]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2454 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2455 { "[ff01::8:800:200C:417A/16]:8080", STATUS_INVALID_PARAMETER, 0xbadf00d, 0xbeef,
2456 { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2457 };
2458 const unsigned int ipv6_ex_testcount = sizeof(ipv6_ex_tests) / sizeof(ipv6_ex_tests[0]);
2459 const char *simple_ip = "::";
2460 unsigned int i;
2461
2462 if (!pRtlIpv6StringToAddressExW)
2463 {
2464 skip("RtlIpv6StringToAddressExW not available\n");
2465 /* we can continue, just not test W */
2466 }
2467
2468 if (!pRtlIpv6StringToAddressExA)
2469 {
2470 skip("RtlIpv6StringToAddressExA not available\n");
2471 return;
2472 }
2473
2474 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, &port);
2475 ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2476
2477 init_ip6(&ip, NULL);
2478 init_ip6(&expected_ip, NULL);
2479 scope = 0xbadf00d;
2480 port = 0xbeef;
2481 res = pRtlIpv6StringToAddressExA(NULL, &ip, &scope, &port);
2482 ok(res == STATUS_INVALID_PARAMETER,
2483 "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2484 ok(scope == 0xbadf00d, "[null string] scope = 0x%08x, expected 0xbadf00d\n", scope);
2485 ok(port == 0xbeef, "[null string] port = 0x%08x, expected 0xbeef\n", port);
2486 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2487 "[null string] ip is changed, expected it not to change\n");
2488
2489
2490 init_ip6(&ip, NULL);
2491 scope = 0xbadf00d;
2492 port = 0xbeef;
2493 res = pRtlIpv6StringToAddressExA(simple_ip, NULL, &scope, &port);
2494 ok(res == STATUS_INVALID_PARAMETER,
2495 "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2496 ok(scope == 0xbadf00d, "[null result] scope = 0x%08x, expected 0xbadf00d\n", scope);
2497 ok(port == 0xbeef, "[null result] port = 0x%08x, expected 0xbeef\n", port);
2498 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2499 "[null result] ip is changed, expected it not to change\n");
2500
2501 init_ip6(&ip, NULL);
2502 scope = 0xbadf00d;
2503 port = 0xbeef;
2504 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, NULL, &port);
2505 ok(res == STATUS_INVALID_PARAMETER,
2506 "[null scope] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2507 ok(scope == 0xbadf00d, "[null scope] scope = 0x%08x, expected 0xbadf00d\n", scope);
2508 ok(port == 0xbeef, "[null scope] port = 0x%08x, expected 0xbeef\n", port);
2509 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2510 "[null scope] ip is changed, expected it not to change\n");
2511
2512 init_ip6(&ip, NULL);
2513 scope = 0xbadf00d;
2514 port = 0xbeef;
2515 res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, NULL);
2516 ok(res == STATUS_INVALID_PARAMETER,
2517 "[null port] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2518 ok(scope == 0xbadf00d, "[null port] scope = 0x%08x, expected 0xbadf00d\n", scope);
2519 ok(port == 0xbeef, "[null port] port = 0x%08x, expected 0xbeef\n", port);
2520 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2521 "[null port] ip is changed, expected it not to change\n");
2522
2523 /* sanity check */
2524 ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2525
2526 /* first we run all ip related tests, to make sure someone didnt accidentally reimplement instead of re-use. */
2527 for (i = 0; i < ipv6_testcount; i++)
2528 {
2529 ULONG scope = 0xbadf00d;
2530 USHORT port = 0xbeef;
2531 NTSTATUS expect_ret = (ipv6_tests[i].flags & ex_fail_6) ? STATUS_INVALID_PARAMETER : ipv6_tests[i].res;
2532
2533 if (ipv6_tests[i].flags & ex_skip_6)
2534 continue;
2535
2536 init_ip6(&ip, NULL);
2537 res = pRtlIpv6StringToAddressExA(ipv6_tests[i].address, &ip, &scope, &port);
2538 compare_RtlIpv6StringToAddressExW(ipv6_tests[i].address, &ip, res, scope, port);
2539
2540 /* make sure nothing was changed if this function fails. */
2541 if (res == STATUS_INVALID_PARAMETER)
2542 {
2543 ok(scope == 0xbadf00d, "[%s] scope = 0x%08x, expected 0xbadf00d\n",
2544 ipv6_tests[i].address, scope);
2545 ok(port == 0xbeef, "[%s] port = 0x%08x, expected 0xbeef\n",
2546 ipv6_tests[i].address, port);
2547 }
2548 else
2549 {
2550 ok(scope != 0xbadf00d, "[%s] scope = 0x%08x, not expected 0xbadf00d\n",
2551 ipv6_tests[i].address, scope);
2552 ok(port != 0xbeef, "[%s] port = 0x%08x, not expected 0xbeef\n",
2553 ipv6_tests[i].address, port);
2554 }
2555
2556 if (ipv6_tests[i].flags & win_broken_6)
2557 {
2558 ok(res == expect_ret || broken(res == STATUS_INVALID_PARAMETER),
2559 "[%s] res = 0x%08x, expected 0x%08x\n", ipv6_tests[i].address, res, expect_ret);
2560
2561 if (res == STATUS_INVALID_PARAMETER)
2562 continue;
2563 }
2564 else
2565 {
2566 ok(res == expect_ret, "[%s] res = 0x%08x, expected 0x%08x\n",
2567 ipv6_tests[i].address, res, expect_ret);
2568 }
2569
2570 /* If ex fails but non-ex does not we cannot check if the part that is converted
2571 before it failed was correct, since there is no data for it in the table. */
2572 if (res == expect_ret)
2573 {
2574 init_ip6(&expected_ip, ipv6_tests[i].ip);
2575 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2576 "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2577 ipv6_tests[i].address,
2578 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2579 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2580 expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2581 expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2582 }
2583 }
2584
2585 /* now we run scope / port related tests */
2586 for (i = 0; i < ipv6_ex_testcount; i++)
2587 {
2588 scope = 0xbadf00d;
2589 port = 0xbeef;
2590 init_ip6(&ip, NULL);
2591 res = pRtlIpv6StringToAddressExA(ipv6_ex_tests[i].address, &ip, &scope, &port);
2592 compare_RtlIpv6StringToAddressExW(ipv6_ex_tests[i].address, &ip, res, scope, port);
2593
2594 ok(res == ipv6_ex_tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
2595 ipv6_ex_tests[i].address, res, ipv6_ex_tests[i].res);
2596 ok(scope == ipv6_ex_tests[i].scope, "[%s] scope = 0x%08x, expected 0x%08x\n",
2597 ipv6_ex_tests[i].address, scope, ipv6_ex_tests[i].scope);
2598 ok(port == ipv6_ex_tests[i].port, "[%s] port = 0x%08x, expected 0x%08x\n",
2599 ipv6_ex_tests[i].address, port, ipv6_ex_tests[i].port);
2600
2601 init_ip6(&expected_ip, ipv6_ex_tests[i].ip);
2602 ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2603 "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2604 ipv6_ex_tests[i].address,
2605 ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2606 ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2607 expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2608 expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2609 }
2610 }
2611
2612 static void test_LdrAddRefDll(void)
2613 {
2614 HMODULE mod, mod2;
2615 NTSTATUS status;
2616 BOOL ret;
2617
2618 if (!pLdrAddRefDll)
2619 {
2620 win_skip( "LdrAddRefDll not supported\n" );
2621 return;
2622 }
2623
2624 mod = LoadLibraryA("comctl32.dll");
2625 ok(mod != NULL, "got %p\n", mod);
2626 ret = FreeLibrary(mod);
2627 ok(ret, "got %d\n", ret);
2628
2629 mod2 = GetModuleHandleA("comctl32.dll");
2630 ok(mod2 == NULL, "got %p\n", mod2);
2631
2632 /* load, addref and release 2 times */
2633 mod = LoadLibraryA("comctl32.dll");
2634 ok(mod != NULL, "got %p\n", mod);
2635 status = pLdrAddRefDll(0, mod);
2636 ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2637 ret = FreeLibrary(mod);
2638 ok(ret, "got %d\n", ret);
2639
2640 mod2 = GetModuleHandleA("comctl32.dll");
2641 ok(mod2 != NULL, "got %p\n", mod2);
2642 ret = FreeLibrary(mod);
2643 ok(ret, "got %d\n", ret);
2644
2645 mod2 = GetModuleHandleA("comctl32.dll");
2646 ok(mod2 == NULL, "got %p\n", mod2);
2647
2648 /* pin refcount */
2649 mod = LoadLibraryA("comctl32.dll");
2650 ok(mod != NULL, "got %p\n", mod);
2651 status = pLdrAddRefDll(LDR_ADDREF_DLL_PIN, mod);
2652 ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2653
2654 ret = FreeLibrary(mod);
2655 ok(ret, "got %d\n", ret);
2656 ret = FreeLibrary(mod);
2657 ok(ret, "got %d\n", ret);
2658 ret = FreeLibrary(mod);
2659 ok(ret, "got %d\n", ret);
2660 ret = FreeLibrary(mod);
2661 ok(ret, "got %d\n", ret);
2662
2663 mod2 = GetModuleHandleA("comctl32.dll");
2664 ok(mod2 != NULL, "got %p\n", mod2);
2665 }
2666
2667 static void test_LdrLockLoaderLock(void)
2668 {
2669 ULONG_PTR magic;
2670 ULONG result;
2671 NTSTATUS status;
2672
2673 if (!pLdrLockLoaderLock)
2674 {
2675 win_skip("LdrLockLoaderLock() is not available\n");
2676 return;
2677 }
2678
2679 /* invalid flags */
2680 result = 10;
2681 magic = 0xdeadbeef;
2682 status = pLdrLockLoaderLock(0x10, &result, &magic);
2683 ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2684 ok(result == 0, "got %d\n", result);
2685 ok(magic == 0, "got %lx\n", magic);
2686
2687 magic = 0xdeadbeef;
2688 status = pLdrLockLoaderLock(0x10, NULL, &magic);
2689 ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2690 ok(magic == 0, "got %lx\n", magic);
2691
2692 result = 10;
2693 status = pLdrLockLoaderLock(0x10, &result, NULL);
2694 ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2695 ok(result == 0, "got %d\n", result);
2696
2697 /* non-blocking mode, result is null */
2698 magic = 0xdeadbeef;
2699 status = pLdrLockLoaderLock(0x2, NULL, &magic);
2700 ok(status == STATUS_INVALID_PARAMETER_2, "got 0x%08x\n", status);
2701 ok(magic == 0, "got %lx\n", magic);
2702
2703 /* magic pointer is null */
2704 result = 10;
2705 status = pLdrLockLoaderLock(0, &result, NULL);
2706 ok(status == STATUS_INVALID_PARAMETER_3, "got 0x%08x\n", status);
2707 ok(result == 0, "got %d\n", result);
2708
2709 /* lock in non-blocking mode */
2710 result = 0;
2711 magic = 0;
2712 status = pLdrLockLoaderLock(0x2, &result, &magic);
2713 ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2714 ok(result == 1, "got %d\n", result);
2715 ok(magic != 0, "got %lx\n", magic);
2716 pLdrUnlockLoaderLock(0, magic);
2717 }
2718
2719 static void test_RtlGetCompressionWorkSpaceSize(void)
2720 {
2721 ULONG compress_workspace, decompress_workspace;
2722 NTSTATUS status;
2723
2724 if (!pRtlGetCompressionWorkSpaceSize)
2725 {
2726 win_skip("RtlGetCompressionWorkSpaceSize is not available\n");
2727 return;
2728 }
2729
2730 status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_NONE, &compress_workspace,
2731 &decompress_workspace);
2732 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2733
2734 status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_DEFAULT, &compress_workspace,
2735 &decompress_workspace);
2736 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2737
2738 status = pRtlGetCompressionWorkSpaceSize(0xFF, &compress_workspace, &decompress_workspace);
2739 ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
2740
2741 compress_workspace = decompress_workspace = 0xdeadbeef;
2742 status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
2743 &decompress_workspace);
2744 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2745 ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
2746 ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %d\n", decompress_workspace);
2747
2748 compress_workspace = decompress_workspace = 0xdeadbeef;
2749 status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM,
2750 &compress_workspace, &decompress_workspace);
2751 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2752 ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
2753 ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %d\n", decompress_workspace);
2754 }
2755
2756 /* helper for test_RtlDecompressBuffer, checks if a chunk is incomplete */
2757 static BOOL is_incomplete_chunk(const UCHAR *compressed, ULONG compressed_size, BOOL check_all)
2758 {
2759 ULONG chunk_size;
2760 if (compressed_size <= sizeof(WORD))
2761 return TRUE;
2762 while (compressed_size >= sizeof(WORD))
2763 {
2764 chunk_size = (*(WORD *)compressed & 0xFFF) + 1;
2765 if (compressed_size < sizeof(WORD) + chunk_size)
2766 return TRUE;
2767 if (!check_all)
2768 break;
2769 compressed += sizeof(WORD) + chunk_size;
2770 compressed_size -= sizeof(WORD) + chunk_size;
2771 }
2772 return FALSE;
2773 }
2774
2775 #define DECOMPRESS_BROKEN_TRUNCATED 1
2776 #define DECOMPRESS_BROKEN_FRAGMENT 2
2777
2778 static void test_RtlDecompressBuffer(void)
2779 {
2780 static const UCHAR test_multiple_chunks[] = {0x03, 0x30, 'W', 'i', 'n', 'e',
2781 0x03, 0x30, 'W', 'i', 'n', 'e'};
2782 static const struct
2783 {
2784 UCHAR compressed[32];
2785 ULONG compressed_size;
2786 NTSTATUS status;
2787 UCHAR uncompressed[32];
2788 ULONG uncompressed_size;
2789 DWORD broken_flags;
2790 }
2791 test_lznt[] =
2792 {
2793 /* 4 byte uncompressed chunk */
2794 {
2795 {0x03, 0x30, 'W', 'i', 'n', 'e'},
2796 6,
2797 STATUS_SUCCESS,
2798 "Wine",
2799 4,
2800 DECOMPRESS_BROKEN_FRAGMENT
2801 },
2802 /* 8 byte uncompressed chunk */
2803 {
2804 {0x07, 0x30, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2805 10,
2806 STATUS_SUCCESS,
2807 "WineWine",
2808 8,
2809 DECOMPRESS_BROKEN_FRAGMENT
2810 },
2811 /* 4 byte compressed chunk */
2812 {
2813 {0x04, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2814 7,
2815 STATUS_SUCCESS,
2816 "Wine",
2817 4
2818 },
2819 /* 8 byte compressed chunk */
2820 {
2821 {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2822 11,
2823 STATUS_SUCCESS,
2824 "WineWine",
2825 8
2826 },
2827 /* compressed chunk using backwards reference */
2828 {
2829 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x01, 0x30},
2830 9,
2831 STATUS_SUCCESS,
2832 "WineWine",
2833 8,
2834 DECOMPRESS_BROKEN_TRUNCATED
2835 },
2836 /* compressed chunk using backwards reference with length > bytes_read */
2837 {
2838 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x30},
2839 9,
2840 STATUS_SUCCESS,
2841 "WineWineWine",
2842 12,
2843 DECOMPRESS_BROKEN_TRUNCATED
2844 },
2845 /* same as above, but unused bits != 0 */
2846 {
2847 {0x06, 0xB0, 0x30, 'W', 'i', 'n', 'e', 0x01, 0x30},
2848 9,
2849 STATUS_SUCCESS,
2850 "WineWine",
2851 8,
2852 DECOMPRESS_BROKEN_TRUNCATED
2853 },
2854 /* compressed chunk without backwards reference and unused bits != 0 */
2855 {
2856 {0x01, 0xB0, 0x02, 'W'},
2857 4,
2858 STATUS_SUCCESS,
2859 "W",
2860 1
2861 },
2862 /* termination sequence after first chunk */
2863 {
2864 {0x03, 0x30, 'W', 'i', 'n', 'e', 0x00, 0x00, 0x03, 0x30, 'W', 'i', 'n', 'e'},
2865 14,
2866 STATUS_SUCCESS,
2867 "Wine",
2868 4,
2869 DECOMPRESS_BROKEN_FRAGMENT
2870 },
2871 /* compressed chunk using backwards reference with 4 bit offset, 12 bit length */
2872 {
2873 {0x14, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2874 0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2875 0x01, 0x01, 0xF0},
2876 23,
2877 STATUS_SUCCESS,
2878 "ABCDEFGHIJKLMNOPABCD",
2879 20,
2880 DECOMPRESS_BROKEN_TRUNCATED
2881 },
2882 /* compressed chunk using backwards reference with 5 bit offset, 11 bit length */
2883 {
2884 {0x15, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2885 0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2886 0x02, 'A', 0x00, 0x78},
2887 24,
2888 STATUS_SUCCESS,
2889 "ABCDEFGHIJKLMNOPABCD",
2890 20,
2891 DECOMPRESS_BROKEN_TRUNCATED
2892 },
2893 /* uncompressed chunk with invalid magic */
2894 {
2895 {0x03, 0x20, 'W', 'i', 'n', 'e'},
2896 6,
2897 STATUS_SUCCESS,
2898 "Wine",
2899 4,
2900 DECOMPRESS_BROKEN_FRAGMENT
2901 },
2902 /* compressed chunk with invalid magic */
2903 {
2904 {0x04, 0xA0, 0x00, 'W', 'i', 'n', 'e'},
2905 7,
2906 STATUS_SUCCESS,
2907 "Wine",
2908 4
2909 },
2910 /* garbage byte after end of buffer */
2911 {
2912 {0x00, 0xB0, 0x02, 0x01},
2913 4,
2914 STATUS_SUCCESS,
2915 "",
2916 0
2917 },
2918 /* empty compressed chunk */
2919 {
2920 {0x00, 0xB0, 0x00},
2921 3,
2922 STATUS_SUCCESS,
2923 "",
2924 0
2925 },
2926 /* empty compressed chunk with unused bits != 0 */
2927 {
2928 {0x00, 0xB0, 0x01},
2929 3,
2930 STATUS_SUCCESS,
2931 "",
2932 0
2933 },
2934 /* empty input buffer */
2935 {
2936 {0},
2937 0,
2938 STATUS_BAD_COMPRESSION_BUFFER,
2939 },
2940 /* incomplete chunk header */
2941 {
2942 {0x01},
2943 1,
2944 STATUS_BAD_COMPRESSION_BUFFER
2945 },
2946 /* incomplete chunk header */
2947 {
2948 {0x00, 0x30},
2949 2,
2950 STATUS_BAD_COMPRESSION_BUFFER
2951 },
2952 /* compressed chunk with invalid backwards reference */
2953 {
2954 {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x40},
2955 9,
2956 STATUS_BAD_COMPRESSION_BUFFER
2957 },
2958 /* compressed chunk with incomplete backwards reference */
2959 {
2960 {0x05, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05},
2961 8,
2962 STATUS_BAD_COMPRESSION_BUFFER
2963 },
2964 /* incomplete uncompressed chunk */
2965 {
2966 {0x07, 0x30, 'W', 'i', 'n', 'e'},
2967 6,
2968 STATUS_BAD_COMPRESSION_BUFFER
2969 },
2970 /* incomplete compressed chunk */
2971 {
2972 {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2973 7,
2974 STATUS_BAD_COMPRESSION_BUFFER
2975 },
2976 /* two compressed chunks, the second one incomplete */
2977 {
2978 {0x00, 0xB0, 0x02, 0x00, 0xB0},
2979 5,
2980 STATUS_BAD_COMPRESSION_BUFFER,
2981 }
2982 };
2983
2984 static UCHAR buf[0x2000], workspace[0x1000];
2985 NTSTATUS status, expected_status;
2986 ULONG final_size;
2987 int i;
2988
2989 if (!pRtlDecompressBuffer || !pRtlDecompressFragment)
2990 {
2991 win_skip("RtlDecompressBuffer or RtlDecompressFragment is not available\n");
2992 return;
2993 }
2994
2995 /* test compression format / engine */
2996 final_size = 0xdeadbeef;
2997 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf) - 1, test_lznt[0].compressed,
2998 test_lznt[0].compressed_size, &final_size);
2999 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
3000 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3001
3002 final_size = 0xdeadbeef;
3003 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf) - 1, test_lznt[0].compressed,
3004 test_lznt[0].compressed_size, &final_size);
3005 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
3006 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3007
3008 final_size = 0xdeadbeef;
3009 status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf) - 1, test_lznt[0].compressed,
3010 test_lznt[0].compressed_size, &final_size);
3011 ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
3012 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3013
3014 /* regular tests for RtlDecompressBuffer */
3015 for (i = 0; i < sizeof(test_lznt) / sizeof(test_lznt[0]); i++)
3016 {
3017 trace("Running test %d (compressed_size=%d, compressed_size=%d, status=%d)\n",
3018 i, test_lznt[i].compressed_size, test_lznt[i].compressed_size, test_lznt[i].status);
3019
3020 /* test with very big buffer */
3021 final_size = 0xdeadbeef;
3022 memset(buf, 0x11, sizeof(buf));
3023 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3024 test_lznt[i].compressed_size, &final_size);
3025 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3026 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
3027 if (!status)
3028 {
3029 ok(final_size == test_lznt[i].uncompressed_size,
3030 "%d: got wrong final_size %d\n", i, final_size);
3031 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
3032 "%d: got wrong decoded data\n", i);
3033 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
3034 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
3035 }
3036
3037 /* test that modifier for compression engine is ignored */
3038 final_size = 0xdeadbeef;
3039 memset(buf, 0x11, sizeof(buf));
3040 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buf, sizeof(buf),
3041 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
3042 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3043 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
3044 if (!status)
3045 {
3046 ok(final_size == test_lznt[i].uncompressed_size,
3047 "%d: got wrong final_size %d\n", i, final_size);
3048 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
3049 "%d: got wrong decoded data\n", i);
3050 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
3051 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
3052 }
3053
3054 /* test with expected output size */
3055 if (test_lznt[i].uncompressed_size > 0)
3056 {
3057 final_size = 0xdeadbeef;
3058 memset(buf, 0x11, sizeof(buf));
3059 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size,
3060 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
3061 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
3062 if (!status)
3063 {
3064 ok(final_size == test_lznt[i].uncompressed_size,
3065 "%d: got wrong final_size %d\n", i, final_size);
3066 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
3067 "%d: got wrong decoded data\n", i);
3068 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
3069 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
3070 }
3071 }
3072
3073 /* test with smaller output size */
3074 if (test_lznt[i].uncompressed_size > 1)
3075 {
3076 final_size = 0xdeadbeef;
3077 memset(buf, 0x11, sizeof(buf));
3078 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size - 1,
3079 test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
3080 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3081 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_TRUNCATED)), "%d: got wrong status 0x%08x\n", i, status);
3082 if (!status)
3083 {
3084 ok(final_size == test_lznt[i].uncompressed_size - 1,
3085 "%d: got wrong final_size %d\n", i, final_size);
3086 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size - 1),
3087 "%d: got wrong decoded data\n", i);
3088 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
3089 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size - 1);
3090 }
3091 }
3092
3093 /* test with zero output size */
3094 final_size = 0xdeadbeef;
3095 memset(buf, 0x11, sizeof(buf));
3096 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_lznt[i].compressed,
3097 test_lznt[i].compressed_size, &final_size);
3098 if (is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, FALSE))
3099 {
3100 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
3101 }
3102 else
3103 {
3104 ok(status == STATUS_SUCCESS, "%d: got wrong status 0x%08x\n", i, status);
3105 ok(final_size == 0, "%d: got wrong final_size %d\n", i, final_size);
3106 ok(buf[0] == 0x11, "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
3107 }
3108
3109 /* test RtlDecompressBuffer with offset = 0 */
3110 final_size = 0xdeadbeef;
3111 memset(buf, 0x11, sizeof(buf));
3112 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3113 test_lznt[i].compressed_size, 0, &final_size, workspace);
3114 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3115 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
3116 if (!status)
3117 {
3118 ok(final_size == test_lznt[i].uncompressed_size,
3119 "%d: got wrong final_size %d\n", i, final_size);
3120 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
3121 "%d: got wrong decoded data\n", i);
3122 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
3123 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size);
3124 }
3125
3126 /* test RtlDecompressBuffer with offset = 1 */
3127 final_size = 0xdeadbeef;
3128 memset(buf, 0x11, sizeof(buf));
3129 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3130 test_lznt[i].compressed_size, 1, &final_size, workspace);
3131 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3132 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
3133 if (!status)
3134 {
3135 if (test_lznt[i].uncompressed_size == 0)
3136 {
3137 todo_wine
3138 ok(final_size == 4095,
3139 "%d: got wrong final size %d\n", i, final_size);
3140 /* Buffer doesn't contain any useful value on Windows */
3141 ok(buf[4095] == 0x11,
3142 "%d: buf[4095] overwritten\n", i);
3143 }
3144 else
3145 {
3146 ok(final_size == test_lznt[i].uncompressed_size - 1,
3147 "%d: got wrong final_size %d\n", i, final_size);
3148 ok(!memcmp(buf, test_lznt[i].uncompressed + 1, test_lznt[i].uncompressed_size - 1),
3149 "%d: got wrong decoded data\n", i);
3150 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
3151 "%d: buf[%d] overwritten\n", i, test_lznt[i].uncompressed_size - 1);
3152 }
3153 }
3154
3155 /* test RtlDecompressBuffer with offset = 4095 */
3156 final_size = 0xdeadbeef;
3157 memset(buf, 0x11, sizeof(buf));
3158 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3159 test_lznt[i].compressed_size, 4095, &final_size, workspace);
3160 ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
3161 (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
3162 if (!status)
3163 {
3164 todo_wine
3165 ok(final_size == 1,
3166 "%d: got wrong final size %d\n", i, final_size);
3167 todo_wine
3168 ok(buf[0] == 0,
3169 "%d: padding is not zero\n", i);
3170 ok(buf[1] == 0x11,
3171 "%d: buf[1] overwritten\n", i);
3172 }
3173
3174 /* test RtlDecompressBuffer with offset = 4096 */
3175 final_size = 0xdeadbeef;
3176 memset(buf, 0x11, sizeof(buf));
3177 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3178 test_lznt[i].compressed_size, 4096, &final_size, workspace);
3179 expected_status = is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, TRUE) ?
3180 test_lznt[i].status : STATUS_SUCCESS;
3181 ok(status == expected_status, "%d: got wrong status 0x%08x, expected 0x%08x\n", i, status, expected_status);
3182 if (!status)
3183 {
3184 ok(final_size == 0,
3185 "%d: got wrong final size %d\n", i, final_size);
3186 ok(buf[0] == 0x11,
3187 "%d: buf[4096] overwritten\n", i);
3188 }
3189 }
3190
3191 /* test decoding of multiple chunks with pRtlDecompressBuffer */
3192 final_size = 0xdeadbeef;
3193 memset(buf, 0x11, sizeof(buf));
3194 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
3195 sizeof(test_multiple_chunks), &final_size);
3196 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3197 "got wrong status 0x%08x\n", status);
3198 if (!status)
3199 {
3200 ok(final_size == 4100, "got wrong final_size %d\n", final_size);
3201 ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
3202 ok(buf[4] == 0 && buf[4095] == 0, "padding is not zero\n");
3203 ok(!memcmp(buf + 4096, "Wine", 4), "got wrong decoded data at offset 4096\n");
3204 ok(buf[4100] == 0x11, "buf[4100] overwritten\n");
3205 }
3206
3207 final_size = 0xdeadbeef;
3208 memset(buf, 0x11, sizeof(buf));
3209 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4097, test_multiple_chunks,
3210 sizeof(test_multiple_chunks), &final_size);
3211 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3212 "got wrong status 0x%08x\n", status);
3213 if (!status)
3214 {
3215 ok(final_size == 4097, "got wrong final_size %d\n", final_size);
3216 ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
3217 ok(buf[4] == 0 && buf[4095] == 0, "padding is not zero\n");
3218 ok(buf[4096], "got wrong decoded data at offset 4096\n");
3219 ok(buf[4097] == 0x11, "buf[4097] overwritten\n");
3220 }
3221
3222 final_size = 0xdeadbeef;
3223 memset(buf, 0x11, sizeof(buf));
3224 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4096, test_multiple_chunks,
3225 sizeof(test_multiple_chunks), &final_size);
3226 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3227 "got wrong status 0x%08x\n", status);
3228 if (!status)
3229 {
3230 ok(final_size == 4, "got wrong final_size %d\n", final_size);
3231 ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
3232 ok(buf[4] == 0x11, "buf[4] overwritten\n");
3233 }
3234
3235 final_size = 0xdeadbeef;
3236 memset(buf, 0x11, sizeof(buf));
3237 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 4, test_multiple_chunks,
3238 sizeof(test_multiple_chunks), &final_size);
3239 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3240 if (!status)
3241 {
3242 ok(final_size == 4, "got wrong final_size %d\n", final_size);
3243 ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
3244 ok(buf[4] == 0x11, "buf[4] overwritten\n");
3245 }
3246
3247 final_size = 0xdeadbeef;
3248 memset(buf, 0x11, sizeof(buf));
3249 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 3, test_multiple_chunks,
3250 sizeof(test_multiple_chunks), &final_size);
3251 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3252 if (!status)
3253 {
3254 ok(final_size == 3, "got wrong final_size %d\n", final_size);
3255 ok(!memcmp(buf, "Wine", 3), "got wrong decoded data at offset 0\n");
3256 ok(buf[3] == 0x11, "buf[3] overwritten\n");
3257 }
3258
3259 final_size = 0xdeadbeef;
3260 memset(buf, 0x11, sizeof(buf));
3261 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_multiple_chunks,
3262 sizeof(test_multiple_chunks), &final_size);
3263 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3264 if (!status)
3265 {
3266 ok(final_size == 0, "got wrong final_size %d\n", final_size);
3267 ok(buf[0] == 0x11, "buf[0] overwritten\n");
3268 }
3269
3270 /* test multiple chunks in combination with RtlDecompressBuffer and offset=1 */
3271 final_size = 0xdeadbeef;
3272 memset(buf, 0x11, sizeof(buf));
3273 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
3274 sizeof(test_multiple_chunks), 1, &final_size, workspace);
3275 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3276 "got wrong status 0x%08x\n", status);
3277 if (!status)
3278 {
3279 ok(final_size == 4099, "got wrong final_size %d\n", final_size);
3280 ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
3281 ok(buf[3] == 0 && buf[4094] == 0, "padding is not zero\n");
3282 ok(!memcmp(buf + 4095, "Wine", 4), "got wrong decoded data at offset 4095\n");
3283 ok(buf[4099] == 0x11, "buf[4099] overwritten\n");
3284 }
3285
3286 final_size = 0xdeadbeef;
3287 memset(buf, 0x11, sizeof(buf));
3288 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 4096, test_multiple_chunks,
3289 sizeof(test_multiple_chunks), 1, &final_size, workspace);
3290 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3291 "got wrong status 0x%08x\n", status);
3292 if (!status)
3293 {
3294 ok(final_size == 4096, "got wrong final_size %d\n", final_size);
3295 ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
3296 ok(buf[3] == 0 && buf[4094] == 0, "padding is not zero\n");
3297 ok(buf[4095] == 'W', "got wrong decoded data at offset 4095\n");
3298 ok(buf[4096] == 0x11, "buf[4096] overwritten\n");
3299 }
3300
3301 final_size = 0xdeadbeef;
3302 memset(buf, 0x11, sizeof(buf));
3303 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 4095, test_multiple_chunks,
3304 sizeof(test_multiple_chunks), 1, &final_size, workspace);
3305 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3306 "got wrong status 0x%08x\n", status);
3307 if (!status)
3308 {
3309 ok(final_size == 3, "got wrong final_size %d\n", final_size);
3310 ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
3311 ok(buf[4] == 0x11, "buf[4] overwritten\n");
3312 }
3313
3314 final_size = 0xdeadbeef;
3315 memset(buf, 0x11, sizeof(buf));
3316 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, 3, test_multiple_chunks,
3317 sizeof(test_multiple_chunks), 1, &final_size, workspace);
3318 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3319 if (!status)
3320 {
3321 ok(final_size == 3, "got wrong final_size %d\n", final_size);
3322 ok(!memcmp(buf, "ine", 3), "got wrong decoded data at offset 0\n");
3323 ok(buf[3] == 0x11, "buf[3] overwritten\n");
3324 }
3325
3326 /* test multiple chunks in combination with RtlDecompressBuffer and offset=4 */
3327 final_size = 0xdeadbeef;
3328 memset(buf, 0x11, sizeof(buf));
3329 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
3330 sizeof(test_multiple_chunks), 4, &final_size, workspace);
3331 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3332 "got wrong status 0x%08x\n", status);
3333 if (!status)
3334 {
3335 ok(final_size == 4096, "got wrong final_size %d\n", final_size);
3336 ok(buf[0] == 0 && buf[4091] == 0, "padding is not zero\n");
3337 ok(!memcmp(buf + 4092, "Wine", 4), "got wrong decoded data at offset 4092\n");
3338 ok(buf[4096] == 0x11, "buf[4096] overwritten\n");
3339 }
3340
3341 final_size = 0xdeadbeef;
3342 memset(buf, 0x11, sizeof(buf));
3343 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
3344 sizeof(test_multiple_chunks), 4095, &final_size, workspace);
3345 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3346 "got wrong status 0x%08x\n", status);
3347 if (!status)
3348 {
3349 ok(final_size == 5, "got wrong final_size %d\n", final_size);
3350 ok(buf[0] == 0, "padding is not zero\n");
3351 ok(!memcmp(buf + 1, "Wine", 4), "got wrong decoded data at offset 1\n");
3352 ok(buf[5] == 0x11, "buf[5] overwritten\n");
3353 }
3354
3355 final_size = 0xdeadbeef;
3356 memset(buf, 0x11, sizeof(buf));
3357 status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_multiple_chunks,
3358 sizeof(test_multiple_chunks), 4096, &final_size, workspace);
3359 ok(status == STATUS_SUCCESS || broken(status == STATUS_BAD_COMPRESSION_BUFFER),
3360 "got wrong status 0x%08x\n", status);
3361 if (!status)
3362 {
3363 ok(final_size == 4, "got wrong final_size %d\n", final_size);
3364 ok(!memcmp(buf, "Wine", 4), "got wrong decoded data at offset 0\n");
3365 ok(buf[4] == 0x11, "buf[4] overwritten\n");
3366 }
3367
3368 }
3369
3370 static void test_RtlCompressBuffer(void)
3371 {
3372 ULONG compress_workspace, decompress_workspace;
3373 static const UCHAR test_buffer[] = "WineWineWine";
3374 static UCHAR buf1[0x1000], buf2[0x1000], *workspace;
3375 ULONG final_size, buf_size;
3376 NTSTATUS status;
3377
3378 if (!pRtlCompressBuffer || !pRtlGetCompressionWorkSpaceSize)
3379 {
3380 win_skip("RtlCompressBuffer or RtlGetCompressionWorkSpaceSize is not available\n");
3381 return;
3382 }
3383
3384 compress_workspace = decompress_workspace = 0xdeadbeef;
3385 status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
3386 &decompress_workspace);
3387 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3388 ok(compress_workspace != 0, "got wrong compress_workspace %d\n", compress_workspace);
3389
3390 workspace = HeapAlloc( GetProcessHeap(), 0, compress_workspace );
3391 ok(workspace != NULL, "HeapAlloc failed %x\n", GetLastError());
3392
3393 /* test compression format / engine */
3394 final_size = 0xdeadbeef;
3395 status = pRtlCompressBuffer(COMPRESSION_FORMAT_NONE, test_buffer, sizeof(test_buffer),
3396 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
3397 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
3398 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3399
3400 final_size = 0xdeadbeef;
3401 status = pRtlCompressBuffer(COMPRESSION_FORMAT_DEFAULT, test_buffer, sizeof(test_buffer),
3402 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
3403 ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
3404 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3405
3406 final_size = 0xdeadbeef;
3407 status = pRtlCompressBuffer(0xFF, test_buffer, sizeof(test_buffer),
3408 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
3409 ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
3410 ok(final_size == 0xdeadbeef, "got wrong final_size %d\n", final_size);
3411
3412 /* test compression */
3413 final_size = 0xdeadbeef;
3414 memset(buf1, 0x11, sizeof(buf1));
3415 status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
3416 buf1, sizeof(buf1), 4096, &final_size, workspace);
3417 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3418 ok((*(WORD *)buf1 & 0x7000) == 0x3000, "no chunk signature found %04x\n", *(WORD *)buf1);
3419 buf_size = final_size;
3420 todo_wine
3421 ok(final_size < sizeof(test_buffer), "got wrong final_size %d\n", final_size);
3422
3423 /* test decompression */
3424 final_size = 0xdeadbeef;
3425 memset(buf2, 0x11, sizeof(buf2));
3426 status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf2, sizeof(buf2),
3427 buf1, buf_size, &final_size);
3428 ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
3429 ok(final_size == sizeof(test_buffer), "got wrong final_size %d\n", final_size);
3430 ok(!memcmp(buf2, test_buffer, sizeof(test_buffer)), "got wrong decoded data\n");
3431 ok(buf2[sizeof(test_buffer)] == 0x11, "buf[%u] overwritten\n", (DWORD)sizeof(test_buffer));
3432
3433 /* buffer too small */
3434 final_size = 0xdeadbeef;
3435 memset(buf1, 0x11, sizeof(buf1));
3436 status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
3437 buf1, 4, 4096, &final_size, workspace);
3438 ok(status == STATUS_BUFFER_TOO_SMALL, "got wrong status 0x%08x\n", status);
3439
3440 HeapFree(GetProcessHeap(), 0, workspace);
3441 }
3442
3443 START_TEST(rtl)
3444 {
3445 InitFunctionPtrs();
3446
3447 #ifdef __i386__
3448 test_WinSqm();
3449 #else
3450 skip("stdcall-style parameter checks are not supported on this platform.\n");
3451 #endif
3452
3453 test_RtlCompareMemory();
3454 test_RtlCompareMemoryUlong();
3455 test_RtlMoveMemory();
3456 test_RtlFillMemory();
3457 test_RtlFillMemoryUlong();
3458 test_RtlZeroMemory();
3459 test_RtlUlonglongByteSwap();
3460 test_RtlUniform();
3461 test_RtlRandom();
3462 test_RtlAreAllAccessesGranted();
3463 test_RtlAreAnyAccessesGranted();
3464 test_RtlComputeCrc32();
3465 test_HandleTables();
3466 test_RtlAllocateAndInitializeSid();
3467 test_RtlDeleteTimer();
3468 test_RtlThreadErrorMode();
3469 test_LdrProcessRelocationBlock();
3470 test_RtlIpv4AddressToString();
3471 test_RtlIpv4AddressToStringEx();
3472 test_RtlIpv4StringToAddress();
3473 test_RtlIpv4StringToAddressEx();
3474 test_RtlIpv6AddressToString();
3475 test_RtlIpv6AddressToStringEx();
3476 test_RtlIpv6StringToAddress();
3477 test_RtlIpv6StringToAddressEx();
3478 test_LdrAddRefDll();
3479 test_LdrLockLoaderLock();
3480 test_RtlGetCompressionWorkSpaceSize();
3481 test_RtlDecompressBuffer();
3482 test_RtlCompressBuffer();
3483 }