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