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