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