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