Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / third_party / BaseClasses / arithutil.cpp
1 //------------------------------------------------------------------------------
2 // File: ArithUtil.cpp
3 //
4 // Desc: DirectShow base classes - implements helper classes for building
5 //       multimedia filters.
6 //
7 // Copyright (c) 1992-2004 Microsoft Corporation.  All rights reserved.
8 //------------------------------------------------------------------------------
9
10 #include <pjmedia-videodev/config.h>
11
12 #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
13
14 #include <streams.h>
15
16 //
17 //  Declare function from largeint.h we need so that PPC can build
18 //
19
20 //
21 // Enlarged integer divide - 64-bits / 32-bits > 32-bits
22 //
23
24 #ifndef _X86_
25
26 #define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x)))
27
28 __inline
29 ULONG
30 WINAPI
31 EnlargedUnsignedDivide (
32     IN ULARGE_INTEGER Dividend,
33     IN ULONG Divisor,
34     IN PULONG Remainder
35     )
36 {
37         // return remainder if necessary
38         if (Remainder != NULL)
39                 *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor);
40         return (ULONG)(LLtoU64(Dividend) / Divisor);
41 }
42
43 #else
44 __inline
45 ULONG
46 WINAPI
47 EnlargedUnsignedDivide (
48     IN ULARGE_INTEGER Dividend,
49     IN ULONG Divisor,
50     IN PULONG Remainder
51     )
52 {
53     ULONG ulResult;
54     _asm {
55         mov eax,Dividend.LowPart
56         mov edx,Dividend.HighPart
57         mov ecx,Remainder
58         div Divisor
59         or  ecx,ecx
60         jz  short label
61         mov [ecx],edx
62 label:
63         mov ulResult,eax
64     }
65     return ulResult;
66 }
67 #endif
68
69
70 /*  Arithmetic functions to help with time format conversions
71 */
72
73 #ifdef _M_ALPHA
74 // work around bug in version 12.00.8385 of the alpha compiler where
75 // UInt32x32To64 sign-extends its arguments (?)
76 #undef UInt32x32To64
77 #define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff))
78 #endif
79
80 /*   Compute (a * b + d) / c */
81 LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d)
82 {
83     /*  Compute the absolute values to avoid signed arithmetic problems */
84     ULARGE_INTEGER ua, ub;
85     DWORDLONG uc;
86
87     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
88     ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b);
89     uc          = (DWORDLONG)(c >= 0 ? c : -c);
90     BOOL bSign = (a < 0) ^ (b < 0);
91
92     /*  Do long multiplication */
93     ULARGE_INTEGER p[2];
94     p[0].QuadPart  = UInt32x32To64(ua.LowPart, ub.LowPart);
95
96     /*  This next computation cannot overflow into p[1].HighPart because
97         the max number we can compute here is:
98
99                  (2 ** 32 - 1) * (2 ** 32 - 1) +  // ua.LowPart * ub.LowPart
100     (2 ** 32) *  (2 ** 31) * (2 ** 32 - 1) * 2    // x.LowPart * y.HighPart * 2
101
102     == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1)
103     == 2 ** 96 - 2 ** 33 + 1
104     < 2 ** 96
105     */
106
107     ULARGE_INTEGER x;
108     x.QuadPart     = UInt32x32To64(ua.LowPart, ub.HighPart) +
109                      UInt32x32To64(ua.HighPart, ub.LowPart) +
110                      p[0].HighPart;
111     p[0].HighPart  = x.LowPart;
112     p[1].QuadPart  = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart;
113
114     if (d != 0) {
115         ULARGE_INTEGER ud[2];
116         if (bSign) {
117             ud[0].QuadPart = (DWORDLONG)(-d);
118             if (d > 0) {
119                 /*  -d < 0 */
120                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
121             } else {
122                 ud[1].QuadPart = (DWORDLONG)0;
123             }
124         } else {
125             ud[0].QuadPart = (DWORDLONG)d;
126             if (d < 0) {
127                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
128             } else {
129                 ud[1].QuadPart = (DWORDLONG)0;
130             }
131         }
132         /*  Now do extended addition */
133         ULARGE_INTEGER uliTotal;
134
135         /*  Add ls DWORDs */
136         uliTotal.QuadPart  = (DWORDLONG)ud[0].LowPart + p[0].LowPart;
137         p[0].LowPart       = uliTotal.LowPart;
138
139         /*  Propagate carry */
140         uliTotal.LowPart   = uliTotal.HighPart;
141         uliTotal.HighPart  = 0;
142
143         /*  Add 2nd most ls DWORDs */
144         uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart;
145         p[0].HighPart      = uliTotal.LowPart;
146
147         /*  Propagate carry */
148         uliTotal.LowPart   = uliTotal.HighPart;
149         uliTotal.HighPart  = 0;
150
151         /*  Add MS DWORDLONGs - no carry expected */
152         p[1].QuadPart     += ud[1].QuadPart + uliTotal.QuadPart;
153
154         /*  Now see if we got a sign change from the addition */
155         if ((LONG)p[1].HighPart < 0) {
156             bSign = !bSign;
157
158             /*  Negate the current value (ugh!) */
159             p[0].QuadPart  = ~p[0].QuadPart;
160             p[1].QuadPart  = ~p[1].QuadPart;
161             p[0].QuadPart += 1;
162             p[1].QuadPart += (p[0].QuadPart == 0);
163         }
164     }
165
166     /*  Now for the division */
167     if (c < 0) {
168         bSign = !bSign;
169     }
170
171
172     /*  This will catch c == 0 and overflow */
173     if (uc <= p[1].QuadPart) {
174         return bSign ? (LONGLONG)0x8000000000000000 :
175                        (LONGLONG)0x7FFFFFFFFFFFFFFF;
176     }
177
178     DWORDLONG ullResult;
179
180     /*  Do the division */
181     /*  If the dividend is a DWORD_LONG use the compiler */
182     if (p[1].QuadPart == 0) {
183         ullResult = p[0].QuadPart / uc;
184         return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult;
185     }
186
187     /*  If the divisor is a DWORD then its simpler */
188     ULARGE_INTEGER ulic;
189     ulic.QuadPart = uc;
190     if (ulic.HighPart == 0) {
191         ULARGE_INTEGER uliDividend;
192         ULARGE_INTEGER uliResult;
193         DWORD dwDivisor = (DWORD)uc;
194         // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor);
195         uliDividend.HighPart = p[1].LowPart;
196         uliDividend.LowPart = p[0].HighPart;
197 #ifndef USE_LARGEINT
198         uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor);
199         p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor);
200         uliResult.LowPart = 0;
201         uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart;
202 #else
203         /*  NOTE - this routine will take exceptions if
204             the result does not fit in a DWORD
205         */
206         if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
207             uliResult.HighPart = EnlargedUnsignedDivide(
208                                      uliDividend,
209                                      dwDivisor,
210                                      &p[0].HighPart);
211         } else {
212             uliResult.HighPart = 0;
213         }
214         uliResult.LowPart = EnlargedUnsignedDivide(
215                                  p[0],
216                                  dwDivisor,
217                                  NULL);
218 #endif
219         return bSign ? -(LONGLONG)uliResult.QuadPart :
220                         (LONGLONG)uliResult.QuadPart;
221     }
222
223
224     ullResult = 0;
225
226     /*  OK - do long division */
227     for (int i = 0; i < 64; i++) {
228         ullResult <<= 1;
229
230         /*  Shift 128 bit p left 1 */
231         p[1].QuadPart <<= 1;
232         if ((p[0].HighPart & 0x80000000) != 0) {
233             p[1].LowPart++;
234         }
235         p[0].QuadPart <<= 1;
236
237         /*  Compare */
238         if (uc <= p[1].QuadPart) {
239             p[1].QuadPart -= uc;
240             ullResult += 1;
241         }
242     }
243
244     return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult;
245 }
246
247 LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d)
248 {
249     ULARGE_INTEGER ua;
250     DWORD ub;
251     DWORD uc;
252
253     /*  Compute the absolute values to avoid signed arithmetic problems */
254     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
255     ub = (DWORD)(b >= 0 ? b : -b);
256     uc = (DWORD)(c >= 0 ? c : -c);
257     BOOL bSign = (a < 0) ^ (b < 0);
258
259     /*  Do long multiplication */
260     ULARGE_INTEGER p0;
261     DWORD p1;
262     p0.QuadPart  = UInt32x32To64(ua.LowPart, ub);
263
264     if (ua.HighPart != 0) {
265         ULARGE_INTEGER x;
266         x.QuadPart     = UInt32x32To64(ua.HighPart, ub) + p0.HighPart;
267         p0.HighPart  = x.LowPart;
268         p1   = x.HighPart;
269     } else {
270         p1 = 0;
271     }
272
273     if (d != 0) {
274         ULARGE_INTEGER ud0;
275         DWORD ud1;
276
277         if (bSign) {
278             //
279             //  Cast d to LONGLONG first otherwise -0x80000000 sign extends
280             //  incorrectly
281             //
282             ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d);
283             if (d > 0) {
284                 /*  -d < 0 */
285                 ud1 = (DWORD)-1;
286             } else {
287                 ud1 = (DWORD)0;
288             }
289         } else {
290             ud0.QuadPart = (DWORDLONG)d;
291             if (d < 0) {
292                 ud1 = (DWORD)-1;
293             } else {
294                 ud1 = (DWORD)0;
295             }
296         }
297         /*  Now do extended addition */
298         ULARGE_INTEGER uliTotal;
299
300         /*  Add ls DWORDs */
301         uliTotal.QuadPart  = (DWORDLONG)ud0.LowPart + p0.LowPart;
302         p0.LowPart       = uliTotal.LowPart;
303
304         /*  Propagate carry */
305         uliTotal.LowPart   = uliTotal.HighPart;
306         uliTotal.HighPart  = 0;
307
308         /*  Add 2nd most ls DWORDs */
309         uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart;
310         p0.HighPart      = uliTotal.LowPart;
311
312         /*  Add MS DWORDLONGs - no carry expected */
313         p1 += ud1 + uliTotal.HighPart;
314
315         /*  Now see if we got a sign change from the addition */
316         if ((LONG)p1 < 0) {
317             bSign = !bSign;
318
319             /*  Negate the current value (ugh!) */
320             p0.QuadPart  = ~p0.QuadPart;
321             p1 = ~p1;
322             p0.QuadPart += 1;
323             p1 += (p0.QuadPart == 0);
324         }
325     }
326
327     /*  Now for the division */
328     if (c < 0) {
329         bSign = !bSign;
330     }
331
332
333     /*  This will catch c == 0 and overflow */
334     if (uc <= p1) {
335         return bSign ? (LONGLONG)0x8000000000000000 :
336                        (LONGLONG)0x7FFFFFFFFFFFFFFF;
337     }
338
339     /*  Do the division */
340
341     /*  If the divisor is a DWORD then its simpler */
342     ULARGE_INTEGER uliDividend;
343     ULARGE_INTEGER uliResult;
344     DWORD dwDivisor = uc;
345     uliDividend.HighPart = p1;
346     uliDividend.LowPart = p0.HighPart;
347     /*  NOTE - this routine will take exceptions if
348         the result does not fit in a DWORD
349     */
350     if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
351         uliResult.HighPart = EnlargedUnsignedDivide(
352                                  uliDividend,
353                                  dwDivisor,
354                                  &p0.HighPart);
355     } else {
356         uliResult.HighPart = 0;
357     }
358     uliResult.LowPart = EnlargedUnsignedDivide(
359                              p0,
360                              dwDivisor,
361                              NULL);
362     return bSign ? -(LONGLONG)uliResult.QuadPart :
363                     (LONGLONG)uliResult.QuadPart;
364 }
365
366 #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */