ntdll: Reimplemented _chkstk and _alloca_probe directly in assembly.
[wine] / dlls / ntdll / large_int.c
1 /*
2  * Large integer functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  * Copyright 2003 Thomas Mertes
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winternl.h"
28
29 /*
30  * Note: we use LONGLONG instead of LARGE_INTEGER, because
31  * the latter is a structure and the calling convention for
32  * returning a structure would not be binary-compatible.
33  *
34  * FIXME: for platforms that don't have a native LONGLONG type,
35  * we should define LONGLONG as a structure similar to LARGE_INTEGER
36  * and do everything by hand. You are welcome to do it...
37  */
38
39 /******************************************************************************
40  *        RtlLargeIntegerAdd   (NTDLL.@)
41  *
42  * Add two 64 bit integers.
43  *
44  * PARAMS
45  *  a [I] Initial number.
46  *  b [I] Number to add to a.
47  *
48  * RETURNS
49  *  The sum of a and b.
50  */
51 LONGLONG WINAPI RtlLargeIntegerAdd( LONGLONG a, LONGLONG b )
52 {
53     return a + b;
54 }
55
56
57 /******************************************************************************
58  *        RtlLargeIntegerSubtract   (NTDLL.@)
59  *
60  * Subtract two 64 bit integers.
61  *
62  * PARAMS
63  *  a [I] Initial number.
64  *  b [I] Number to subtract from a.
65  *
66  * RETURNS
67  *  The difference of a and b.
68  */
69 LONGLONG WINAPI RtlLargeIntegerSubtract( LONGLONG a, LONGLONG b )
70 {
71     return a - b;
72 }
73
74
75 /******************************************************************************
76  *        RtlLargeIntegerNegate   (NTDLL.@)
77  *
78  * Negate a 64 bit integer.
79  *
80  * PARAMS
81  *  a     [I] Initial number.
82  *
83  * RETURNS
84  *  The value of a negated.
85  */
86 LONGLONG WINAPI RtlLargeIntegerNegate( LONGLONG a )
87 {
88     return -a;
89 }
90
91
92 /******************************************************************************
93  *        RtlLargeIntegerShiftLeft   (NTDLL.@)
94  *
95  * Perform a shift left on a 64 bit integer.
96  *
97  * PARAMS
98  *  a     [I] Initial number.
99  *  count [I] Number of bits to shift by
100  *
101  * RETURNS
102  *  The value of a following the shift.
103  */
104 LONGLONG WINAPI RtlLargeIntegerShiftLeft( LONGLONG a, INT count )
105 {
106     return a << count;
107 }
108
109
110 /******************************************************************************
111  *        RtlLargeIntegerShiftRight   (NTDLL.@)
112  *
113  * Perform a shift right on a 64 bit integer.
114  *
115  * PARAMS
116  *  a     [I] Initial number.
117  *  count [I] Number of bits to shift by
118  *
119  * RETURNS
120  *  The value of a following the shift.
121  */
122 LONGLONG WINAPI RtlLargeIntegerShiftRight( LONGLONG a, INT count )
123 {
124     return (ULONGLONG)a >> count;
125 }
126
127
128 /******************************************************************************
129  *        RtlLargeIntegerArithmeticShift   (NTDLL.@)
130  *
131  * Perform an arithmetic shift right on a 64 bit integer.
132  *
133  * PARAMS
134  *  a     [I] Initial number.
135  *  count [I] Number of bits to shift by
136  *
137  * RETURNS
138  *  The value of a following the shift.
139  */
140 LONGLONG WINAPI RtlLargeIntegerArithmeticShift( LONGLONG a, INT count )
141 {
142     /* FIXME: gcc does arithmetic shift here, but it may not be true on all platforms */
143     return a >> count;
144 }
145
146
147 /******************************************************************************
148  *        RtlLargeIntegerDivide   (NTDLL.@)
149  *
150  * Divide one 64 bit unsigned integer by another, with remainder.
151  *
152  * PARAMS
153  *  a   [I] Initial number.
154  *  b   [I] Number to divide a by
155  *  rem [O] Destination for remainder
156  *
157  * RETURNS
158  *  The dividend of a and b. If rem is non-NULL it is set to the remainder.
159  *
160  * FIXME
161  *  Should it be signed division instead?
162  */
163 ULONGLONG WINAPI RtlLargeIntegerDivide( ULONGLONG a, ULONGLONG b, ULONGLONG *rem )
164 {
165     ULONGLONG ret = a / b;
166     if (rem) *rem = a - ret * b;
167     return ret;
168 }
169
170
171 /******************************************************************************
172  *        RtlConvertLongToLargeInteger   (NTDLL.@)
173  *
174  * Convert a 32 bit integer into 64 bits.
175  *
176  * PARAMS
177  *  a [I] Number to convert
178  *
179  * RETURNS
180  *  a.
181  */
182 LONGLONG WINAPI RtlConvertLongToLargeInteger( LONG a )
183 {
184     return a;
185 }
186
187
188 /******************************************************************************
189  *        RtlConvertUlongToLargeInteger   (NTDLL.@)
190  *
191  * Convert a 32 bit unsigned integer into 64 bits.
192  *
193  * PARAMS
194  *  a [I] Number to convert
195  *
196  * RETURNS
197  *  a.
198  */
199 ULONGLONG WINAPI RtlConvertUlongToLargeInteger( ULONG a )
200 {
201     return a;
202 }
203
204
205 /******************************************************************************
206  *        RtlEnlargedIntegerMultiply   (NTDLL.@)
207  *
208  * Multiply two integers giving a 64 bit integer result.
209  *
210  * PARAMS
211  *  a [I] Initial number.
212  *  b [I] Number to multiply a by.
213  *
214  * RETURNS
215  *  The product of a and b.
216  */
217 LONGLONG WINAPI RtlEnlargedIntegerMultiply( INT a, INT b )
218 {
219     return (LONGLONG)a * b;
220 }
221
222
223 /******************************************************************************
224  *        RtlEnlargedUnsignedMultiply   (NTDLL.@)
225  *
226  * Multiply two unsigned integers giving a 64 bit unsigned integer result.
227  *
228  * PARAMS
229  *  a [I] Initial number.
230  *  b [I] Number to multiply a by.
231  *
232  * RETURNS
233  *  The product of a and b.
234  */
235 ULONGLONG WINAPI RtlEnlargedUnsignedMultiply( UINT a, UINT b )
236 {
237     return (ULONGLONG)a * b;
238 }
239
240
241 /******************************************************************************
242  *        RtlEnlargedUnsignedDivide   (NTDLL.@)
243  *
244  * Divide one 64 bit unsigned integer by a 32 bit unsigned integer, with remainder.
245  *
246  * PARAMS
247  *  a      [I] Initial number.
248  *  b      [I] Number to divide a by
249  *  remptr [O] Destination for remainder
250  *
251  * RETURNS
252  *  The dividend of a and b. If remptr is non-NULL it is set to the remainder.
253  */
254 UINT WINAPI RtlEnlargedUnsignedDivide( ULONGLONG a, UINT b, UINT *remptr )
255 {
256 #if defined(__i386__) && defined(__GNUC__)
257     UINT ret, rem, p1, p2;
258
259     p1 = a >> 32;
260     p2 = a &  0xffffffffLL;
261
262     __asm__("div %4,%%eax"
263             : "=a" (ret), "=d" (rem)
264             : "0" (p2), "1" (p1), "g" (b) );
265     if (remptr) *remptr = rem;
266     return ret;
267 #else
268     UINT ret = a / b;
269     if (remptr) *remptr = a % b;
270     return ret;
271 #endif
272 }
273
274
275 /******************************************************************************
276  *        RtlExtendedLargeIntegerDivide   (NTDLL.@)
277  *
278  * Divide one 64 bit integer by a 32 bit integer, with remainder.
279  *
280  * PARAMS
281  *  a   [I] Initial number.
282  *  b   [I] Number to divide a by
283  *  rem [O] Destination for remainder
284  *
285  * RETURNS
286  *  The dividend of a and b. If rem is non-NULL it is set to the remainder.
287  */
288 LONGLONG WINAPI RtlExtendedLargeIntegerDivide( LONGLONG a, INT b, INT *rem )
289 {
290     LONGLONG ret = a / b;
291     if (rem) *rem = a - b * ret;
292     return ret;
293 }
294
295
296 /******************************************************************************
297  *        RtlExtendedIntegerMultiply   (NTDLL.@)
298  *
299  * Multiply one 64 bit integer by another 32 bit integer.
300  *
301  * PARAMS
302  *  a [I] Initial number.
303  *  b [I] Number to multiply a by.
304  *
305  * RETURNS
306  *  The product of a and b.
307  */
308 LONGLONG WINAPI RtlExtendedIntegerMultiply( LONGLONG a, INT b )
309 {
310     return a * b;
311 }
312
313
314 /******************************************************************************
315  *        RtlExtendedMagicDivide   (NTDLL.@)
316  *
317  * Allows replacing a division by a longlong constant with a multiplication by
318  * the inverse constant.
319  *
320  * RETURNS
321  *  (dividend * inverse_divisor) >> (64 + shift)
322  *
323  * NOTES
324  *  If the divisor of a division is constant, the constants inverse_divisor and
325  *  shift must be chosen such that inverse_divisor = 2^(64 + shift) / divisor.
326  *  Then we have RtlExtendedMagicDivide(dividend,inverse_divisor,shift) ==
327  *  dividend * inverse_divisor / 2^(64 + shift) == dividend / divisor.
328  *
329  *  The Parameter inverse_divisor although defined as LONGLONG is used as
330  *  ULONGLONG.
331  */
332 #define LOWER_32(A) ((A) & 0xffffffff)
333 #define UPPER_32(A) ((A) >> 32)
334 LONGLONG WINAPI RtlExtendedMagicDivide(
335     LONGLONG dividend,        /* [I] Dividend to be divided by the constant divisor */
336     LONGLONG inverse_divisor, /* [I] Constant computed manually as 2^(64+shift) / divisor */
337     INT shift)                /* [I] Constant shift chosen to make inverse_divisor as big as possible for 64 bits */
338 {
339     ULONGLONG dividend_high;
340     ULONGLONG dividend_low;
341     ULONGLONG inverse_divisor_high;
342     ULONGLONG inverse_divisor_low;
343     ULONGLONG ah_bl;
344     ULONGLONG al_bh;
345     LONGLONG result;
346     int positive;
347
348     if (dividend < 0) {
349         dividend_high = UPPER_32((ULONGLONG) -dividend);
350         dividend_low =  LOWER_32((ULONGLONG) -dividend);
351         positive = 0;
352     } else {
353         dividend_high = UPPER_32((ULONGLONG) dividend);
354         dividend_low =  LOWER_32((ULONGLONG) dividend);
355         positive = 1;
356     } /* if */
357     inverse_divisor_high = UPPER_32((ULONGLONG) inverse_divisor);
358     inverse_divisor_low =  LOWER_32((ULONGLONG) inverse_divisor);
359
360     ah_bl = dividend_high * inverse_divisor_low;
361     al_bh = dividend_low * inverse_divisor_high;
362
363     result = (LONGLONG) ((dividend_high * inverse_divisor_high +
364             UPPER_32(ah_bl) +
365             UPPER_32(al_bh) +
366             UPPER_32(LOWER_32(ah_bl) + LOWER_32(al_bh) +
367                      UPPER_32(dividend_low * inverse_divisor_low))) >> shift);
368
369     if (positive) {
370         return result;
371     } else {
372         return -result;
373     } /* if */
374 }
375
376
377 /******************************************************************************
378  *      RtlLargeIntegerToChar   [NTDLL.@]
379  *
380  * Convert an unsigned large integer to a character string.
381  *
382  * RETURNS
383  *  Success: STATUS_SUCCESS. str contains the converted number
384  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
385  *           STATUS_BUFFER_OVERFLOW, if str would be larger than length.
386  *           STATUS_ACCESS_VIOLATION, if str is NULL.
387  *
388  * NOTES
389  *  Instead of base 0 it uses 10 as base.
390  *  Writes at most length characters to the string str.
391  *  Str is '\0' terminated when length allows it.
392  *  When str fits exactly in length characters the '\0' is omitted.
393  *  If value_ptr is NULL it crashes, as the native function does.
394  *
395  * DIFFERENCES
396  * - Accept base 0 as 10 instead of crashing as native function does.
397  * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for
398  *   base 2, 8 and 16 when the value is larger than 0xFFFFFFFF.
399  */
400 NTSTATUS WINAPI RtlLargeIntegerToChar(
401     const ULONGLONG *value_ptr, /* [I] Pointer to the value to be converted */
402     ULONG base,                 /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
403     ULONG length,               /* [I] Length of the str buffer in bytes */
404     PCHAR str)                  /* [O] Destination for the converted value */
405 {
406     ULONGLONG value = *value_ptr;
407     CHAR buffer[65];
408     PCHAR pos;
409     CHAR digit;
410     ULONG len;
411
412     if (base == 0) {
413         base = 10;
414     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
415         return STATUS_INVALID_PARAMETER;
416     } /* if */
417
418     pos = &buffer[64];
419     *pos = '\0';
420
421     do {
422         pos--;
423         digit = value % base;
424         value = value / base;
425         if (digit < 10) {
426             *pos = '0' + digit;
427         } else {
428             *pos = 'A' + digit - 10;
429         } /* if */
430     } while (value != 0L);
431
432     len = &buffer[64] - pos;
433     if (len > length) {
434         return STATUS_BUFFER_OVERFLOW;
435     } else if (str == NULL) {
436         return STATUS_ACCESS_VIOLATION;
437     } else if (len == length) {
438         memcpy(str, pos, len);
439     } else {
440         memcpy(str, pos, len + 1);
441     } /* if */
442     return STATUS_SUCCESS;
443 }
444
445
446 /**************************************************************************
447  *      RtlInt64ToUnicodeString (NTDLL.@)
448  *
449  * Convert a large unsigned integer to a '\0' terminated unicode string.
450  *
451  * RETURNS
452  *  Success: STATUS_SUCCESS. str contains the converted number
453  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
454  *           STATUS_BUFFER_OVERFLOW, if str is too small to hold the string
455  *                  (with the '\0' termination). In this case str->Length
456  *                  is set to the length, the string would have (which can
457  *                  be larger than the MaximumLength).
458  *
459  * NOTES
460  *  Instead of base 0 it uses 10 as base.
461  *  If str is NULL it crashes, as the native function does.
462  *
463  * DIFFERENCES
464  * - Accept base 0 as 10 instead of crashing as native function does.
465  * - Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
466  *   The native function does this when the string would be longer than 31
467  *   characters even when the string parameter is long enough.
468  * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for
469  *   base 2, 8 and 16 when the value is larger than 0xFFFFFFFF. 
470  */
471 NTSTATUS WINAPI RtlInt64ToUnicodeString(
472     ULONGLONG value,     /* [I] Value to be converted */
473     ULONG base,          /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
474     UNICODE_STRING *str) /* [O] Destination for the converted value */
475 {
476     WCHAR buffer[65];
477     PWCHAR pos;
478     WCHAR digit;
479
480     if (base == 0) {
481         base = 10;
482     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
483         return STATUS_INVALID_PARAMETER;
484     } /* if */
485
486     pos = &buffer[64];
487     *pos = '\0';
488
489     do {
490         pos--;
491         digit = value % base;
492         value = value / base;
493         if (digit < 10) {
494             *pos = '0' + digit;
495         } else {
496             *pos = 'A' + digit - 10;
497         } /* if */
498     } while (value != 0L);
499
500     str->Length = (&buffer[64] - pos) * sizeof(WCHAR);
501     if (str->Length >= str->MaximumLength) {
502         return STATUS_BUFFER_OVERFLOW;
503     } else {
504         memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR));
505     } /* if */
506     return STATUS_SUCCESS;
507 }
508
509
510 /******************************************************************************
511  *        _alldiv   (NTDLL.@)
512  *
513  * Divide two 64 bit unsigned integers.
514  *
515  * PARAMS
516  *  a [I] Initial number.
517  *  b [I] Number to multiply a by.
518  *
519  * RETURNS
520  *  The dividend of a and b.
521  */
522 LONGLONG WINAPI _alldiv( LONGLONG a, LONGLONG b )
523 {
524     return a / b;
525 }
526
527
528 /******************************************************************************
529  *        _allmul   (NTDLL.@)
530  *
531  * Multiply two 64 bit integers.
532  *
533  * PARAMS
534  *  a [I] Initial number.
535  *  b [I] Number to multiply a by.
536  *
537  * RETURNS
538  *  The product of a and b.
539  */
540 LONGLONG WINAPI _allmul( LONGLONG a, LONGLONG b )
541 {
542     return a * b;
543 }
544
545
546 /******************************************************************************
547  *        _allrem   (NTDLL.@)
548  *
549  * Calculate the remainder after dividing two 64 bit integers.
550  *
551  * PARAMS
552  *  a [I] Initial number.
553  *  b [I] Number to divide a by.
554  *
555  * RETURNS
556  *  The remainder of a divided by b.
557  */
558 LONGLONG WINAPI _allrem( LONGLONG a, LONGLONG b )
559 {
560     return a % b;
561 }
562
563
564 /******************************************************************************
565  *        _aulldiv   (NTDLL.@)
566  *
567  * Divide two 64 bit unsigned integers.
568  *
569  * PARAMS
570  *  a [I] Initial number.
571  *  b [I] Number to multiply a by.
572  *
573  * RETURNS
574  *  The dividend of a and b.
575  */
576 ULONGLONG WINAPI _aulldiv( ULONGLONG a, ULONGLONG b )
577 {
578     return a / b;
579 }
580
581
582 /******************************************************************************
583  *        _aullrem   (NTDLL.@)
584  *
585  * Calculate the remainder after dividing two 64 bit unsigned integers.
586  *
587  * PARAMS
588  *  a [I] Initial number.
589  *  b [I] Number to divide a by.
590  *
591  * RETURNS
592  *  The remainder of a divided by b.
593  */
594 ULONGLONG WINAPI _aullrem( ULONGLONG a, ULONGLONG b )
595 {
596     return a % b;
597 }