Fix the case of product and company names.
[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 "winbase.h"
27 #include "winreg.h"
28 #include "winternl.h"
29
30 /*
31  * Note: we use LONGLONG instead of LARGE_INTEGER, because
32  * the latter is a structure and the calling convention for
33  * returning a structure would not be binary-compatible.
34  *
35  * FIXME: for platforms that don't have a native LONGLONG type,
36  * we should define LONGLONG as a structure similar to LARGE_INTEGER
37  * and do everything by hand. You are welcome to do it...
38  */
39
40 /******************************************************************************
41  *        RtlLargeIntegerAdd   (NTDLL.@)
42  */
43 LONGLONG WINAPI RtlLargeIntegerAdd( LONGLONG a, LONGLONG b )
44 {
45     return a + b;
46 }
47
48
49 /******************************************************************************
50  *        RtlLargeIntegerSubtract   (NTDLL.@)
51  */
52 LONGLONG WINAPI RtlLargeIntegerSubtract( LONGLONG a, LONGLONG b )
53 {
54     return a - b;
55 }
56
57
58 /******************************************************************************
59  *        RtlLargeIntegerNegate   (NTDLL.@)
60  */
61 LONGLONG WINAPI RtlLargeIntegerNegate( LONGLONG a )
62 {
63     return -a;
64 }
65
66
67 /******************************************************************************
68  *        RtlLargeIntegerShiftLeft   (NTDLL.@)
69  */
70 LONGLONG WINAPI RtlLargeIntegerShiftLeft( LONGLONG a, INT count )
71 {
72     return a << count;
73 }
74
75
76 /******************************************************************************
77  *        RtlLargeIntegerShiftRight   (NTDLL.@)
78  */
79 LONGLONG WINAPI RtlLargeIntegerShiftRight( LONGLONG a, INT count )
80 {
81     return (ULONGLONG)a >> count;
82 }
83
84
85 /******************************************************************************
86  *        RtlLargeIntegerArithmeticShift   (NTDLL.@)
87  */
88 LONGLONG WINAPI RtlLargeIntegerArithmeticShift( LONGLONG a, INT count )
89 {
90     /* FIXME: gcc does arithmetic shift here, but it may not be true on all platforms */
91     return a >> count;
92 }
93
94
95 /******************************************************************************
96  *        RtlLargeIntegerDivide   (NTDLL.@)
97  *
98  * FIXME: should it be signed division instead?
99  */
100 ULONGLONG WINAPI RtlLargeIntegerDivide( ULONGLONG a, ULONGLONG b, ULONGLONG *rem )
101 {
102     ULONGLONG ret = a / b;
103     if (rem) *rem = a - ret * b;
104     return ret;
105 }
106
107
108 /******************************************************************************
109  *        RtlConvertLongToLargeInteger   (NTDLL.@)
110  */
111 LONGLONG WINAPI RtlConvertLongToLargeInteger( LONG a )
112 {
113     return a;
114 }
115
116
117 /******************************************************************************
118  *        RtlConvertUlongToLargeInteger   (NTDLL.@)
119  */
120 ULONGLONG WINAPI RtlConvertUlongToLargeInteger( ULONG a )
121 {
122     return a;
123 }
124
125
126 /******************************************************************************
127  *        RtlEnlargedIntegerMultiply   (NTDLL.@)
128  */
129 LONGLONG WINAPI RtlEnlargedIntegerMultiply( INT a, INT b )
130 {
131     return (LONGLONG)a * b;
132 }
133
134
135 /******************************************************************************
136  *        RtlEnlargedUnsignedMultiply   (NTDLL.@)
137  */
138 ULONGLONG WINAPI RtlEnlargedUnsignedMultiply( UINT a, UINT b )
139 {
140     return (ULONGLONG)a * b;
141 }
142
143
144 /******************************************************************************
145  *        RtlEnlargedUnsignedDivide   (NTDLL.@)
146  */
147 UINT WINAPI RtlEnlargedUnsignedDivide( ULONGLONG a, UINT b, UINT *remptr )
148 {
149 #if defined(__i386__) && defined(__GNUC__)
150     UINT ret, rem, p1, p2;
151
152     p1 = a >> 32;
153     p2 = a &  0xffffffffLL;
154
155     __asm__("div %4,%%eax"
156             : "=a" (ret), "=d" (rem)
157             : "0" (p2), "1" (p1), "g" (b) );
158     if (remptr) *remptr = rem;
159     return ret;
160 #else
161     UINT ret = a / b;
162     if (remptr) *remptr = a % b;
163     return ret;
164 #endif
165 }
166
167
168 /******************************************************************************
169  *        RtlExtendedLargeIntegerDivide   (NTDLL.@)
170  */
171 LONGLONG WINAPI RtlExtendedLargeIntegerDivide( LONGLONG a, INT b, INT *rem )
172 {
173     LONGLONG ret = a / b;
174     if (rem) *rem = a - b * ret;
175     return ret;
176 }
177
178
179 /******************************************************************************
180  *        RtlExtendedIntegerMultiply   (NTDLL.@)
181  */
182 LONGLONG WINAPI RtlExtendedIntegerMultiply( LONGLONG a, INT b )
183 {
184     return a * b;
185 }
186
187
188 /******************************************************************************
189  *        RtlExtendedMagicDivide   (NTDLL.@)
190  *
191  * Allows replacing a division by a longlong constant with a multiplication by
192  * the inverse constant.
193  *
194  * RETURNS
195  *  (dividend * inverse_divisor) >> (64 + shift)
196  *
197  * NOTES
198  *  If the divisor of a division is constant, the constants inverse_divisor and
199  *  shift must be chosen such that inverse_divisor = 2^(64 + shift) / divisor.
200  *  Then we have RtlExtendedMagicDivide(dividend,inverse_divisor,shift) ==
201  *  dividend * inverse_divisor / 2^(64 + shift) == dividend / divisor.
202  *
203  *  The Parameter inverse_divisor although defined as LONGLONG is used as
204  *  ULONGLONG.
205  */
206 #define LOWER_32(A) ((A) & 0xffffffff)
207 #define UPPER_32(A) ((A) >> 32)
208 LONGLONG WINAPI RtlExtendedMagicDivide(
209     LONGLONG dividend,        /* [I] Dividend to be divided by the constant divisor */
210     LONGLONG inverse_divisor, /* [I] Constant computed manually as 2^(64+shift) / divisor */
211     INT shift)                /* [I] Constant shift chosen to make inverse_divisor as big as possible for 64 bits */
212 {
213     ULONGLONG dividend_high;
214     ULONGLONG dividend_low;
215     ULONGLONG inverse_divisor_high;
216     ULONGLONG inverse_divisor_low;
217     ULONGLONG ah_bl;
218     ULONGLONG al_bh;
219     LONGLONG result;
220     int positive;
221
222     if (dividend < 0) {
223         dividend_high = UPPER_32((ULONGLONG) -dividend);
224         dividend_low =  LOWER_32((ULONGLONG) -dividend);
225         positive = 0;
226     } else {
227         dividend_high = UPPER_32((ULONGLONG) dividend);
228         dividend_low =  LOWER_32((ULONGLONG) dividend);
229         positive = 1;
230     } /* if */
231     inverse_divisor_high = UPPER_32((ULONGLONG) inverse_divisor);
232     inverse_divisor_low =  LOWER_32((ULONGLONG) inverse_divisor);
233
234     ah_bl = dividend_high * inverse_divisor_low;
235     al_bh = dividend_low * inverse_divisor_high;
236
237     result = (LONGLONG) ((dividend_high * inverse_divisor_high +
238             UPPER_32(ah_bl) +
239             UPPER_32(al_bh) +
240             UPPER_32(LOWER_32(ah_bl) + LOWER_32(al_bh) +
241                      UPPER_32(dividend_low * inverse_divisor_low))) >> shift);
242
243     if (positive) {
244         return result;
245     } else {
246         return -result;
247     } /* if */
248 }
249
250
251 /******************************************************************************
252  *      RtlLargeIntegerToChar   [NTDLL.@]
253  *
254  * Convert an unsigned large integer to a character string.
255  *
256  * RETURNS
257  *  Success: STATUS_SUCCESS. str contains the converted number
258  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
259  *           STATUS_BUFFER_OVERFLOW, if str would be larger than length.
260  *           STATUS_ACCESS_VIOLATION, if str is NULL.
261  *
262  * NOTES
263  *  Instead of base 0 it uses 10 as base.
264  *  Writes at most length characters to the string str.
265  *  Str is '\0' terminated when length allowes it.
266  *  When str fits exactly in length characters the '\0' is ommitted.
267  *  If value_ptr is NULL it crashes, as the native function does.
268  *
269  * DIFFERENCES
270  * - Accept base 0 as 10 instead of crashing as native function does.
271  * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for
272  *   base 2, 8 and 16 when the value is larger than 0xFFFFFFFF. 
273  */
274 NTSTATUS WINAPI RtlLargeIntegerToChar(
275     const ULONGLONG *value_ptr, /* [I] Pointer to the value to be converted */
276     ULONG base,                 /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
277     ULONG length,               /* [I] Length of the str buffer in bytes */
278     PCHAR str)                  /* [O] Destination for the converted value */
279 {
280     ULONGLONG value = *value_ptr;
281     CHAR buffer[65];
282     PCHAR pos;
283     CHAR digit;
284     ULONG len;
285
286     if (base == 0) {
287         base = 10;
288     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
289         return STATUS_INVALID_PARAMETER;
290     } /* if */
291
292     pos = &buffer[64];
293     *pos = '\0';
294
295     do {
296         pos--;
297         digit = value % base;
298         value = value / base;
299         if (digit < 10) {
300             *pos = '0' + digit;
301         } else {
302             *pos = 'A' + digit - 10;
303         } /* if */
304     } while (value != 0L);
305
306     len = &buffer[64] - pos;
307     if (len > length) {
308         return STATUS_BUFFER_OVERFLOW;
309     } else if (str == NULL) {
310         return STATUS_ACCESS_VIOLATION;
311     } else if (len == length) {
312         memcpy(str, pos, len);
313     } else {
314         memcpy(str, pos, len + 1);
315     } /* if */
316     return STATUS_SUCCESS;
317 }
318
319
320 /**************************************************************************
321  *      RtlInt64ToUnicodeString (NTDLL.@)
322  *
323  * Convert a large unsigned integer to a '\0' terminated unicode string.
324  *
325  * RETURNS
326  *  Success: STATUS_SUCCESS. str contains the converted number
327  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
328  *           STATUS_BUFFER_OVERFLOW, if str is too small to hold the string
329  *                  (with the '\0' termination). In this case str->Length
330  *                  is set to the length, the string would have (which can
331  *                  be larger than the MaximumLength).
332  *
333  * NOTES
334  *  Instead of base 0 it uses 10 as base.
335  *  If str is NULL it crashes, as the native function does.
336  *
337  * DIFFERENCES
338  * - Accept base 0 as 10 instead of crashing as native function does.
339  * - Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
340  *   The native function does this when the string would be longer than 31
341  *   characters even when the string parameter is long enough.
342  * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for
343  *   base 2, 8 and 16 when the value is larger than 0xFFFFFFFF. 
344  */
345 NTSTATUS WINAPI RtlInt64ToUnicodeString(
346     ULONGLONG value,     /* [I] Value to be converted */
347     ULONG base,          /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
348     UNICODE_STRING *str) /* [O] Destination for the converted value */
349 {
350     WCHAR buffer[65];
351     PWCHAR pos;
352     WCHAR digit;
353
354     if (base == 0) {
355         base = 10;
356     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
357         return STATUS_INVALID_PARAMETER;
358     } /* if */
359
360     pos = &buffer[64];
361     *pos = '\0';
362
363     do {
364         pos--;
365         digit = value % base;
366         value = value / base;
367         if (digit < 10) {
368             *pos = '0' + digit;
369         } else {
370             *pos = 'A' + digit - 10;
371         } /* if */
372     } while (value != 0L);
373
374     str->Length = (&buffer[64] - pos) * sizeof(WCHAR);
375     if (str->Length >= str->MaximumLength) {
376         return STATUS_BUFFER_OVERFLOW;
377     } else {
378         memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR));
379     } /* if */
380     return STATUS_SUCCESS;
381 }
382
383
384 /******************************************************************************
385  *        _alldiv   (NTDLL.@)
386  */
387 LONGLONG WINAPI _alldiv( LONGLONG a, LONGLONG b )
388 {
389     return a / b;
390 }
391
392
393 /******************************************************************************
394  *        _allmul   (NTDLL.@)
395  */
396 LONGLONG WINAPI _allmul( LONGLONG a, LONGLONG b )
397 {
398     return a * b;
399 }
400
401
402 /******************************************************************************
403  *        _allrem   (NTDLL.@)
404  */
405 LONGLONG WINAPI _allrem( LONGLONG a, LONGLONG b )
406 {
407     return a % b;
408 }
409
410
411 /******************************************************************************
412  *        _aulldiv   (NTDLL.@)
413  */
414 ULONGLONG WINAPI _aulldiv( ULONGLONG a, ULONGLONG b )
415 {
416     return a / b;
417 }
418
419
420 /******************************************************************************
421  *        _aullrem   (NTDLL.@)
422  */
423 ULONGLONG WINAPI _aullrem( ULONGLONG a, ULONGLONG b )
424 {
425     return a % b;
426 }