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