Take advantage of new winebuild syntax to remove redundant function
[wine] / dlls / ntdll / rtl.c
1 /*
2  * NT basis DLL
3  *
4  * This file contains the Rtl* API functions. These should be implementable.
5  *
6  * Copyright 1996-1998 Marcus Meissner
7  *                1999 Alex Korobka
8  * Crc32 code Copyright 1986 Gary S. Brown (Public domain)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include "windef.h"
32 #include "winerror.h"
33 #include "winternl.h"
34 #include "winreg.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "ntdll_misc.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
40
41
42 static RTL_CRITICAL_SECTION peb_lock = CRITICAL_SECTION_INIT("peb_lock");
43
44 /* CRC polynomial 0xedb88320 */
45 static const DWORD CRC_table[256] =
46 {
47     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
48     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
49     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
50     0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
51     0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
52     0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
53     0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
54     0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
55     0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
56     0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
57     0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
58     0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
59     0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
60     0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
61     0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
62     0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
63     0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
64     0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
65     0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
66     0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
67     0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
68     0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
69     0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
70     0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
71     0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
72     0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
73     0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
74     0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
75     0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
76     0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
77     0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
78     0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
79     0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
80     0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
81     0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
82     0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
83     0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
84     0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
85     0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
86     0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
87     0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
88     0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
89     0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
90 };
91
92 /*
93  *      resource functions
94  */
95
96 /***********************************************************************
97  *           RtlInitializeResource      (NTDLL.@)
98  *
99  * xxxResource() functions implement multiple-reader-single-writer lock.
100  * The code is based on information published in WDJ January 1999 issue.
101  */
102 void WINAPI RtlInitializeResource(LPRTL_RWLOCK rwl)
103 {
104     if( rwl )
105     {
106         rwl->iNumberActive = 0;
107         rwl->uExclusiveWaiters = 0;
108         rwl->uSharedWaiters = 0;
109         rwl->hOwningThreadId = 0;
110         rwl->dwTimeoutBoost = 0; /* no info on this one, default value is 0 */
111         RtlInitializeCriticalSection( &rwl->rtlCS );
112         NtCreateSemaphore( &rwl->hExclusiveReleaseSemaphore, 0, NULL, 0, 65535 );
113         NtCreateSemaphore( &rwl->hSharedReleaseSemaphore, 0, NULL, 0, 65535 );
114     }
115 }
116
117
118 /***********************************************************************
119  *           RtlDeleteResource          (NTDLL.@)
120  */
121 void WINAPI RtlDeleteResource(LPRTL_RWLOCK rwl)
122 {
123     if( rwl )
124     {
125         RtlEnterCriticalSection( &rwl->rtlCS );
126         if( rwl->iNumberActive || rwl->uExclusiveWaiters || rwl->uSharedWaiters )
127             MESSAGE("Deleting active MRSW lock (%p), expect failure\n", rwl );
128         rwl->hOwningThreadId = 0;
129         rwl->uExclusiveWaiters = rwl->uSharedWaiters = 0;
130         rwl->iNumberActive = 0;
131         NtClose( rwl->hExclusiveReleaseSemaphore );
132         NtClose( rwl->hSharedReleaseSemaphore );
133         RtlLeaveCriticalSection( &rwl->rtlCS );
134         RtlDeleteCriticalSection( &rwl->rtlCS );
135     }
136 }
137
138
139 /***********************************************************************
140  *          RtlAcquireResourceExclusive (NTDLL.@)
141  */
142 BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK rwl, BYTE fWait)
143 {
144     BYTE retVal = 0;
145     if( !rwl ) return 0;
146
147 start:
148     RtlEnterCriticalSection( &rwl->rtlCS );
149     if( rwl->iNumberActive == 0 ) /* lock is free */
150     {
151         rwl->iNumberActive = -1;
152         retVal = 1;
153     }
154     else if( rwl->iNumberActive < 0 ) /* exclusive lock in progress */
155     {
156          if( rwl->hOwningThreadId == (HANDLE)GetCurrentThreadId() )
157          {
158              retVal = 1;
159              rwl->iNumberActive--;
160              goto done;
161          }
162 wait:
163          if( fWait )
164          {
165              rwl->uExclusiveWaiters++;
166
167              RtlLeaveCriticalSection( &rwl->rtlCS );
168              if( WaitForSingleObject( rwl->hExclusiveReleaseSemaphore, INFINITE ) == WAIT_FAILED )
169                  goto done;
170              goto start; /* restart the acquisition to avoid deadlocks */
171          }
172     }
173     else  /* one or more shared locks are in progress */
174          if( fWait )
175              goto wait;
176
177     if( retVal == 1 )
178         rwl->hOwningThreadId = (HANDLE)GetCurrentThreadId();
179 done:
180     RtlLeaveCriticalSection( &rwl->rtlCS );
181     return retVal;
182 }
183
184 /***********************************************************************
185  *          RtlAcquireResourceShared    (NTDLL.@)
186  */
187 BYTE WINAPI RtlAcquireResourceShared(LPRTL_RWLOCK rwl, BYTE fWait)
188 {
189     DWORD dwWait = WAIT_FAILED;
190     BYTE retVal = 0;
191     if( !rwl ) return 0;
192
193 start:
194     RtlEnterCriticalSection( &rwl->rtlCS );
195     if( rwl->iNumberActive < 0 )
196     {
197         if( rwl->hOwningThreadId == (HANDLE)GetCurrentThreadId() )
198         {
199             rwl->iNumberActive--;
200             retVal = 1;
201             goto done;
202         }
203
204         if( fWait )
205         {
206             rwl->uSharedWaiters++;
207             RtlLeaveCriticalSection( &rwl->rtlCS );
208             if( (dwWait = WaitForSingleObject( rwl->hSharedReleaseSemaphore, INFINITE )) == WAIT_FAILED )
209                 goto done;
210             goto start;
211         }
212     }
213     else
214     {
215         if( dwWait != WAIT_OBJECT_0 ) /* otherwise RtlReleaseResource() has already done it */
216             rwl->iNumberActive++;
217         retVal = 1;
218     }
219 done:
220     RtlLeaveCriticalSection( &rwl->rtlCS );
221     return retVal;
222 }
223
224
225 /***********************************************************************
226  *           RtlReleaseResource         (NTDLL.@)
227  */
228 void WINAPI RtlReleaseResource(LPRTL_RWLOCK rwl)
229 {
230     RtlEnterCriticalSection( &rwl->rtlCS );
231
232     if( rwl->iNumberActive > 0 ) /* have one or more readers */
233     {
234         if( --rwl->iNumberActive == 0 )
235         {
236             if( rwl->uExclusiveWaiters )
237             {
238 wake_exclusive:
239                 rwl->uExclusiveWaiters--;
240                 NtReleaseSemaphore( rwl->hExclusiveReleaseSemaphore, 1, NULL );
241             }
242         }
243     }
244     else
245     if( rwl->iNumberActive < 0 ) /* have a writer, possibly recursive */
246     {
247         if( ++rwl->iNumberActive == 0 )
248         {
249             rwl->hOwningThreadId = 0;
250             if( rwl->uExclusiveWaiters )
251                 goto wake_exclusive;
252             else
253                 if( rwl->uSharedWaiters )
254                 {
255                     UINT n = rwl->uSharedWaiters;
256                     rwl->iNumberActive = rwl->uSharedWaiters; /* prevent new writers from joining until
257                                                                * all queued readers have done their thing */
258                     rwl->uSharedWaiters = 0;
259                     NtReleaseSemaphore( rwl->hSharedReleaseSemaphore, n, NULL );
260                 }
261         }
262     }
263     RtlLeaveCriticalSection( &rwl->rtlCS );
264 }
265
266
267 /***********************************************************************
268  *           RtlDumpResource            (NTDLL.@)
269  */
270 void WINAPI RtlDumpResource(LPRTL_RWLOCK rwl)
271 {
272     if( rwl )
273     {
274         MESSAGE("RtlDumpResource(%p):\n\tactive count = %i\n\twaiting readers = %i\n\twaiting writers = %i\n",
275                 rwl, rwl->iNumberActive, rwl->uSharedWaiters, rwl->uExclusiveWaiters );
276         if( rwl->iNumberActive )
277             MESSAGE("\towner thread = %p\n", rwl->hOwningThreadId );
278     }
279 }
280
281 /*
282  *      misc functions
283  */
284
285 /******************************************************************************
286  *      DbgPrint        [NTDLL.@]
287  */
288 void WINAPIV DbgPrint(LPCSTR fmt, ...)
289 {
290        char buf[512];
291        va_list args;
292
293        va_start(args, fmt);
294        vsprintf(buf,fmt, args);
295        va_end(args);
296
297         MESSAGE("DbgPrint says: %s",buf);
298         /* hmm, raise exception? */
299 }
300
301 /******************************************************************************
302  *  RtlAcquirePebLock           [NTDLL.@]
303  */
304 VOID WINAPI RtlAcquirePebLock(void)
305 {
306     RtlEnterCriticalSection( &peb_lock );
307 }
308
309 /******************************************************************************
310  *  RtlReleasePebLock           [NTDLL.@]
311  */
312 VOID WINAPI RtlReleasePebLock(void)
313 {
314     RtlLeaveCriticalSection( &peb_lock );
315 }
316
317 /******************************************************************************
318  *  RtlSetEnvironmentVariable           [NTDLL.@]
319  */
320 DWORD WINAPI RtlSetEnvironmentVariable(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) {
321         FIXME("(0x%08lx,%s,%s),stub!\n",x1,debugstr_w(key->Buffer),debugstr_w(val->Buffer));
322         return 0;
323 }
324
325 /******************************************************************************
326  *  RtlNewSecurityObject                [NTDLL.@]
327  */
328 DWORD WINAPI RtlNewSecurityObject(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6) {
329         FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4,x5,x6);
330         return 0;
331 }
332
333 /******************************************************************************
334  *  RtlDeleteSecurityObject             [NTDLL.@]
335  */
336 DWORD WINAPI RtlDeleteSecurityObject(DWORD x1) {
337         FIXME("(0x%08lx),stub!\n",x1);
338         return 0;
339 }
340
341 /**************************************************************************
342  *                 RtlNormalizeProcessParams            [NTDLL.@]
343  */
344 LPVOID WINAPI RtlNormalizeProcessParams(LPVOID x)
345 {
346     FIXME("(%p), stub\n",x);
347     return x;
348 }
349
350 /**************************************************************************
351  *                 RtlGetNtProductType                  [NTDLL.@]
352  */
353 BOOLEAN WINAPI RtlGetNtProductType(LPDWORD type)
354 {
355     FIXME("(%p): stub\n", type);
356     *type=3; /* dunno. 1 for client, 3 for server? */
357     return 1;
358 }
359
360 /**************************************************************************
361  *                 _chkstk                              [NTDLL.@]
362  *
363  * Glorified "enter xxxx".
364  */
365 void WINAPI NTDLL_chkstk( CONTEXT86 *context )
366 {
367     context->Esp -= context->Eax;
368 }
369
370 /**************************************************************************
371  *                 _alloca_probe                        [NTDLL.@]
372  *
373  * Glorified "enter xxxx".
374  */
375 void WINAPI NTDLL_alloca_probe( CONTEXT86 *context )
376 {
377     context->Esp -= context->Eax;
378 }
379
380 /**************************************************************************
381  *                 RtlDosPathNameToNtPathName_U         [NTDLL.@]
382  *
383  * szwDosPath: a fully qualified DOS path name
384  * ntpath:     pointer to a UNICODE_STRING to hold the converted
385  *              path name
386  *
387  * FIXME: Should we not allocate the ntpath buffer under some
388  *         circumstances?
389  *        Are the conversions static? (always prepend '\??\' ?)
390  *        Not really sure about the last two arguments.
391  */
392 BOOLEAN  WINAPI RtlDosPathNameToNtPathName_U(
393         LPWSTR szwDosPath,PUNICODE_STRING ntpath,
394         DWORD x2,DWORD x3)
395 {
396     ULONG length;
397     UNICODE_STRING pathprefix;
398     WCHAR szPrefix[] = { '\\', '?', '?', '\\', 0 };
399
400     FIXME("(%s,%p,%08lx,%08lx) partial stub\n",
401         debugstr_w(szwDosPath),ntpath,x2,x3);
402
403     if ( !szwDosPath )
404         return FALSE;
405
406     if ( !szwDosPath[0] )
407         return FALSE;
408  
409     if ( szwDosPath[1]!= ':' )
410         return FALSE;
411
412     length = strlenW(szwDosPath) * sizeof (WCHAR) + sizeof szPrefix;
413  
414     ntpath->Buffer = RtlAllocateHeap(ntdll_get_process_heap(), 0, length);
415     ntpath->Length = 0;
416     ntpath->MaximumLength = length;
417
418     if ( !ntpath->Buffer )
419         return FALSE;
420
421     RtlInitUnicodeString( &pathprefix, szPrefix );
422     RtlCopyUnicodeString( ntpath, &pathprefix );
423     RtlAppendUnicodeToString( ntpath, szwDosPath );
424
425     return TRUE;
426 }
427
428
429 /******************************************************************************
430  *  RtlCreateEnvironment                [NTDLL.@]
431  */
432 DWORD WINAPI RtlCreateEnvironment(DWORD x1,DWORD x2) {
433         FIXME("(0x%08lx,0x%08lx),stub!\n",x1,x2);
434         return 0;
435 }
436
437
438 /******************************************************************************
439  *  RtlDestroyEnvironment               [NTDLL.@]
440  */
441 DWORD WINAPI RtlDestroyEnvironment(DWORD x) {
442         FIXME("(0x%08lx),stub!\n",x);
443         return 0;
444 }
445
446 /******************************************************************************
447  *  RtlQueryEnvironmentVariable_U               [NTDLL.@]
448  */
449 DWORD WINAPI RtlQueryEnvironmentVariable_U(DWORD x1,PUNICODE_STRING key,PUNICODE_STRING val) {
450         FIXME("(0x%08lx,%s,%p),stub!\n",x1,debugstr_w(key->Buffer),val);
451         return 0;
452 }
453
454 /******************************************************************************
455  *  RtlInitializeGenericTable           [NTDLL.@]
456  */
457 PVOID WINAPI RtlInitializeGenericTable(PVOID pTable, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5)
458 {
459   FIXME("(%p,%p,%p,%p,%p) stub!\n", pTable, arg2, arg3, arg4, arg5);
460   return NULL;
461 }
462
463 /******************************************************************************
464  *  RtlMoveMemory   [NTDLL.@]
465  *
466  * Move a block of memory that may overlap.
467  *
468  * PARAMS
469  *  Destination [O] End destination for block
470  *  Source      [O] Where to start copying from
471  *  Length      [I] Number of bytes to copy
472  *
473  * RETURNS
474  *  Nothing.
475  */
476 #undef RtlMoveMemory
477 VOID WINAPI RtlMoveMemory( VOID *Destination, CONST VOID *Source, SIZE_T Length )
478 {
479     memmove(Destination, Source, Length);
480 }
481
482 /******************************************************************************
483  *  RtlFillMemory   [NTDLL.@]
484  *
485  * Set a block of memory with a value.
486  *
487  * PARAMS
488  *  Destination [O] Block to fill
489  *  Length      [I] Number of bytes to fill
490  *  Fill        [I] Value to set
491  *
492  * RETURNS
493  *  Nothing.
494  */
495 #undef RtlFillMemory
496 VOID WINAPI RtlFillMemory( VOID *Destination, SIZE_T Length, BYTE Fill )
497 {
498     memset(Destination, Fill, Length);
499 }
500
501 /******************************************************************************
502  *  RtlZeroMemory   [NTDLL.@]
503  *
504  * Set a block of memory with 0's.
505  *
506  * PARAMS
507  *  Destination [O] Block to fill
508  *  Length      [I] Number of bytes to fill
509  *
510  * RETURNS
511  *  Nothing.
512  */
513 #undef RtlZeroMemory
514 VOID WINAPI RtlZeroMemory( VOID *Destination, SIZE_T Length )
515 {
516     memset(Destination, 0, Length);
517 }
518
519 /******************************************************************************
520  *  RtlCompareMemory   [NTDLL.@]
521  *
522  * Compare one block of memory with another
523  *
524  * PARAMS
525  *  Source1 [I] Source block
526  *  Source2 [I] Block to compare to Source1
527  *  Length  [I] Number of bytes to fill
528  *
529  * RETURNS
530  *  The length of the first byte at which Source1 and Source2 differ, or Length
531  *  if they are the same.
532  */
533 SIZE_T WINAPI RtlCompareMemory( const VOID *Source1, const VOID *Source2, SIZE_T Length)
534 {
535     SIZE_T i;
536     for(i=0; (i<Length) && (((LPBYTE)Source1)[i]==((LPBYTE)Source2)[i]); i++);
537     return i;
538 }
539
540 /******************************************************************************
541  *  RtlCompareMemoryUlong   [NTDLL.@]
542  *
543  * Compare a block of memory with a value, a ULONG at a time
544  *
545  * PARAMS
546  *  Source1 [I] Source block. This must be ULONG aligned
547  *  Length  [I] Number of bytes to compare. This should be a multiple of 4
548  *  dwVal   [I] Value to compare to
549  *
550  * RETURNS
551  *  The byte position of the first byte at which Source1 is not dwVal.
552  */
553 SIZE_T WINAPI RtlCompareMemoryUlong(const ULONG *Source1, SIZE_T Length, ULONG dwVal)
554 {
555     SIZE_T i;
556     for(i = 0; i < Length/sizeof(ULONG) && Source1[i] == dwVal; i++);
557     return i * sizeof(ULONG);
558 }
559
560 /******************************************************************************
561  *  RtlAssert                           [NTDLL.@]
562  *
563  * Fail a debug assertion.
564  *
565  * RETURNS
566  *  Nothing. This call does not return control to its caller.
567  *
568  * NOTES
569  * Not implemented in non-debug versions.
570  */
571 void WINAPI RtlAssert(LPVOID x1,LPVOID x2,DWORD x3, DWORD x4)
572 {
573         FIXME("(%p,%p,0x%08lx,0x%08lx),stub\n",x1,x2,x3,x4);
574 }
575
576 /******************************************************************************
577  *  RtlGetNtVersionNumbers       [NTDLL.@]
578  *
579  * Get the version numbers of the run time library.
580  *
581  * PARAMS
582  *  major [O] Destination for the Major version
583  *  minor [O] Destination for the Minor version
584  *  build [O] Destination for the Build version
585  *
586  * RETURNS
587  *  Nothing.
588  *
589  * NOTES
590  * Introduced in Windows XP (NT5.1)
591  */
592 void WINAPI RtlGetNtVersionNumbers(LPDWORD major, LPDWORD minor, LPDWORD build)
593 {
594         OSVERSIONINFOEXW versionInfo;
595         versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
596         GetVersionExW((OSVERSIONINFOW*)&versionInfo);
597
598         if (major)
599         {
600                 /* msvcrt.dll as released with XP Home fails in DLLMain() if the
601                  * major version is not 5. So, we should never set a version < 5 ...
602                  * This makes sense since this call didn't exist before XP anyway.
603                  */
604                 *major = versionInfo.dwMajorVersion < 5 ? 5 : versionInfo.dwMajorVersion;
605         }
606
607         if (minor)
608         {
609                 *minor = versionInfo.dwMinorVersion;
610         }
611
612         if (build)
613         {
614                 /* FIXME: Does anybody know the real formula? */
615                 *build = (0xF0000000 | versionInfo.dwBuildNumber);
616         }
617 }
618
619 /*************************************************************************
620  * RtlFillMemoryUlong   [NTDLL.@]
621  *
622  * Fill memory with a 32 bit (dword) value.
623  *
624  * PARAMS
625  *  lpDest  [I] Bitmap pointer
626  *  ulCount [I] Number of dwords to write
627  *  ulValue [I] Value to fill with
628  *
629  * RETURNS
630  *  Nothing.
631  */
632 VOID WINAPI RtlFillMemoryUlong(ULONG* lpDest, ULONG ulCount, ULONG ulValue)
633 {
634   TRACE("(%p,%ld,%ld)\n", lpDest, ulCount, ulValue);
635
636   ulCount /= sizeof(ULONG);
637   while(ulCount--)
638     *lpDest++ = ulValue;
639 }
640
641 /*************************************************************************
642  * RtlGetLongestNtPathLength    [NTDLL.@]
643  *
644  * Get the longest allowed path length
645  *
646  * PARAMS
647  *  None.
648  *
649  * RETURNS
650  *  The longest allowed path length (277 characters under Win2k).
651  */
652 DWORD WINAPI RtlGetLongestNtPathLength(void)
653 {
654   TRACE("()\n");
655   return 277;
656 }
657
658 /*********************************************************************
659  *                  RtlComputeCrc32   [NTDLL.@]
660  *
661  * Calculate the CRC32 checksum of a block of bytes
662  *
663  * PARAMS
664  *  dwInitial [I] Initial CRC value
665  *  pData     [I] Data block
666  *  iLen      [I] Length of the byte block
667  *
668  * RETURNS
669  *  The cumulative CRC32 of dwInitial and iLen bytes of the pData block.
670  */
671 DWORD WINAPI RtlComputeCrc32(DWORD dwInitial, PBYTE pData, INT iLen)
672 {
673   DWORD crc = ~dwInitial;
674
675   TRACE("(%ld,%p,%d)\n", dwInitial, pData, iLen);
676
677   while (iLen > 0)
678   {
679     crc = CRC_table[(crc ^ *pData) & 0xff] ^ (crc >> 8);
680     pData++;
681     iLen--;
682   }
683   return ~crc;
684 }
685
686
687 /*************************************************************************
688  * RtlUlonglongByteSwap    [NTDLL.@]
689  *
690  * Swap the bytes of an unsigned long long value.
691  *
692  * PARAMS
693  *  i [I] Value to swap bytes of
694  *
695  * RETURNS
696  *  The value with its bytes swapped.
697  */
698 ULONGLONG __cdecl RtlUlonglongByteSwap(ULONGLONG i)
699 {
700   return ((ULONGLONG)RtlUlongByteSwap(i) << 32) | RtlUlongByteSwap(i>>32);
701 }
702
703 /*************************************************************************
704  * RtlUlongByteSwap    [NTDLL.@]
705  *
706  * Swap the bytes of an unsigned int value.
707  *
708  * NOTES
709  *  ix86 version takes argument in %ecx. Other systems use the inline version.
710  */
711 #ifdef __i386__
712 __ASM_GLOBAL_FUNC(RtlUlongByteSwap,
713                   "movl %ecx,%eax\n\t"
714                   "bswap %eax\n\t"
715                   "ret");
716 #endif
717
718 /*************************************************************************
719  * RtlUshortByteSwap    [NTDLL.@]
720  *
721  * Swap the bytes of an unsigned short value.
722  *
723  * NOTES
724  *  i386 version takes argument in %cx. Other systems use the inline version.
725  */
726 #ifdef __i386__
727 __ASM_GLOBAL_FUNC(RtlUshortByteSwap,
728                   "movb %ch,%al\n\t"
729                   "movb %cl,%ah\n\t"
730                   "ret");
731 #endif