361 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // File: ArithUtil.cpp
 | |
| //
 | |
| // Desc: DirectShow base classes - implements helper classes for building
 | |
| //       multimedia filters.
 | |
| //
 | |
| // Copyright (c) 1992-2004 Microsoft Corporation.  All rights reserved.
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| #include <streams.h>
 | |
| 
 | |
| //
 | |
| //  Declare function from largeint.h we need so that PPC can build
 | |
| //
 | |
| 
 | |
| //
 | |
| // Enlarged integer divide - 64-bits / 32-bits > 32-bits
 | |
| //
 | |
| 
 | |
| #ifndef _X86_
 | |
| 
 | |
| #define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x)))
 | |
| 
 | |
| __inline
 | |
| ULONG
 | |
| WINAPI
 | |
| EnlargedUnsignedDivide (
 | |
|     IN ULARGE_INTEGER Dividend,
 | |
|     IN ULONG Divisor,
 | |
|     IN PULONG Remainder
 | |
|     )
 | |
| {
 | |
|         // return remainder if necessary
 | |
|         if (Remainder != NULL)
 | |
|                 *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor);
 | |
|         return (ULONG)(LLtoU64(Dividend) / Divisor);
 | |
| }
 | |
| 
 | |
| #else
 | |
| __inline
 | |
| ULONG
 | |
| WINAPI
 | |
| EnlargedUnsignedDivide (
 | |
|     IN ULARGE_INTEGER Dividend,
 | |
|     IN ULONG Divisor,
 | |
|     IN PULONG Remainder
 | |
|     )
 | |
| {
 | |
|     ULONG ulResult;
 | |
|     _asm {
 | |
|         mov eax,Dividend.LowPart
 | |
|         mov edx,Dividend.HighPart
 | |
|         mov ecx,Remainder
 | |
|         div Divisor
 | |
|         or  ecx,ecx
 | |
|         jz  short label
 | |
|         mov [ecx],edx
 | |
| label:
 | |
|         mov ulResult,eax
 | |
|     }
 | |
|     return ulResult;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /*  Arithmetic functions to help with time format conversions
 | |
| */
 | |
| 
 | |
| #ifdef _M_ALPHA
 | |
| // work around bug in version 12.00.8385 of the alpha compiler where
 | |
| // UInt32x32To64 sign-extends its arguments (?)
 | |
| #undef UInt32x32To64
 | |
| #define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff))
 | |
| #endif
 | |
| 
 | |
| /*   Compute (a * b + d) / c */
 | |
| LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d)
 | |
| {
 | |
|     /*  Compute the absolute values to avoid signed arithmetic problems */
 | |
|     ULARGE_INTEGER ua, ub;
 | |
|     DWORDLONG uc;
 | |
| 
 | |
|     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
 | |
|     ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b);
 | |
|     uc          = (DWORDLONG)(c >= 0 ? c : -c);
 | |
|     BOOL bSign = (a < 0) ^ (b < 0);
 | |
| 
 | |
|     /*  Do long multiplication */
 | |
|     ULARGE_INTEGER p[2];
 | |
|     p[0].QuadPart  = UInt32x32To64(ua.LowPart, ub.LowPart);
 | |
| 
 | |
|     /*  This next computation cannot overflow into p[1].HighPart because
 | |
|         the max number we can compute here is:
 | |
| 
 | |
|                  (2 ** 32 - 1) * (2 ** 32 - 1) +  // ua.LowPart * ub.LowPart
 | |
|     (2 ** 32) *  (2 ** 31) * (2 ** 32 - 1) * 2    // x.LowPart * y.HighPart * 2
 | |
| 
 | |
|     == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1)
 | |
|     == 2 ** 96 - 2 ** 33 + 1
 | |
|     < 2 ** 96
 | |
|     */
 | |
| 
 | |
|     ULARGE_INTEGER x;
 | |
|     x.QuadPart     = UInt32x32To64(ua.LowPart, ub.HighPart) +
 | |
|                      UInt32x32To64(ua.HighPart, ub.LowPart) +
 | |
|                      p[0].HighPart;
 | |
|     p[0].HighPart  = x.LowPart;
 | |
|     p[1].QuadPart  = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart;
 | |
| 
 | |
|     if (d != 0) {
 | |
|         ULARGE_INTEGER ud[2];
 | |
|         if (bSign) {
 | |
|             ud[0].QuadPart = (DWORDLONG)(-d);
 | |
|             if (d > 0) {
 | |
|                 /*  -d < 0 */
 | |
|                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
 | |
|             } else {
 | |
|                 ud[1].QuadPart = (DWORDLONG)0;
 | |
|             }
 | |
|         } else {
 | |
|             ud[0].QuadPart = (DWORDLONG)d;
 | |
|             if (d < 0) {
 | |
|                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
 | |
|             } else {
 | |
|                 ud[1].QuadPart = (DWORDLONG)0;
 | |
|             }
 | |
|         }
 | |
|         /*  Now do extended addition */
 | |
|         ULARGE_INTEGER uliTotal;
 | |
| 
 | |
|         /*  Add ls DWORDs */
 | |
|         uliTotal.QuadPart  = (DWORDLONG)ud[0].LowPart + p[0].LowPart;
 | |
|         p[0].LowPart       = uliTotal.LowPart;
 | |
| 
 | |
|         /*  Propagate carry */
 | |
|         uliTotal.LowPart   = uliTotal.HighPart;
 | |
|         uliTotal.HighPart  = 0;
 | |
| 
 | |
|         /*  Add 2nd most ls DWORDs */
 | |
|         uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart;
 | |
|         p[0].HighPart      = uliTotal.LowPart;
 | |
| 
 | |
|         /*  Propagate carry */
 | |
|         uliTotal.LowPart   = uliTotal.HighPart;
 | |
|         uliTotal.HighPart  = 0;
 | |
| 
 | |
|         /*  Add MS DWORDLONGs - no carry expected */
 | |
|         p[1].QuadPart     += ud[1].QuadPart + uliTotal.QuadPart;
 | |
| 
 | |
|         /*  Now see if we got a sign change from the addition */
 | |
|         if ((LONG)p[1].HighPart < 0) {
 | |
|             bSign = !bSign;
 | |
| 
 | |
|             /*  Negate the current value (ugh!) */
 | |
|             p[0].QuadPart  = ~p[0].QuadPart;
 | |
|             p[1].QuadPart  = ~p[1].QuadPart;
 | |
|             p[0].QuadPart += 1;
 | |
|             p[1].QuadPart += (p[0].QuadPart == 0);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*  Now for the division */
 | |
|     if (c < 0) {
 | |
|         bSign = !bSign;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /*  This will catch c == 0 and overflow */
 | |
|     if (uc <= p[1].QuadPart) {
 | |
|         return bSign ? (LONGLONG)0x8000000000000000 :
 | |
|                        (LONGLONG)0x7FFFFFFFFFFFFFFF;
 | |
|     }
 | |
| 
 | |
|     DWORDLONG ullResult;
 | |
| 
 | |
|     /*  Do the division */
 | |
|     /*  If the dividend is a DWORD_LONG use the compiler */
 | |
|     if (p[1].QuadPart == 0) {
 | |
|         ullResult = p[0].QuadPart / uc;
 | |
|         return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult;
 | |
|     }
 | |
| 
 | |
|     /*  If the divisor is a DWORD then its simpler */
 | |
|     ULARGE_INTEGER ulic;
 | |
|     ulic.QuadPart = uc;
 | |
|     if (ulic.HighPart == 0) {
 | |
|         ULARGE_INTEGER uliDividend;
 | |
|         ULARGE_INTEGER uliResult;
 | |
|         DWORD dwDivisor = (DWORD)uc;
 | |
|         // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor);
 | |
|         uliDividend.HighPart = p[1].LowPart;
 | |
|         uliDividend.LowPart = p[0].HighPart;
 | |
| #ifndef USE_LARGEINT
 | |
|         uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor);
 | |
|         p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor);
 | |
|         uliResult.LowPart = 0;
 | |
|         uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart;
 | |
| #else
 | |
|         /*  NOTE - this routine will take exceptions if
 | |
|             the result does not fit in a DWORD
 | |
|         */
 | |
|         if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
 | |
|             uliResult.HighPart = EnlargedUnsignedDivide(
 | |
|                                      uliDividend,
 | |
|                                      dwDivisor,
 | |
|                                      &p[0].HighPart);
 | |
|         } else {
 | |
|             uliResult.HighPart = 0;
 | |
|         }
 | |
|         uliResult.LowPart = EnlargedUnsignedDivide(
 | |
|                                  p[0],
 | |
|                                  dwDivisor,
 | |
|                                  NULL);
 | |
| #endif
 | |
|         return bSign ? -(LONGLONG)uliResult.QuadPart :
 | |
|                         (LONGLONG)uliResult.QuadPart;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ullResult = 0;
 | |
| 
 | |
|     /*  OK - do long division */
 | |
|     for (int i = 0; i < 64; i++) {
 | |
|         ullResult <<= 1;
 | |
| 
 | |
|         /*  Shift 128 bit p left 1 */
 | |
|         p[1].QuadPart <<= 1;
 | |
|         if ((p[0].HighPart & 0x80000000) != 0) {
 | |
|             p[1].LowPart++;
 | |
|         }
 | |
|         p[0].QuadPart <<= 1;
 | |
| 
 | |
|         /*  Compare */
 | |
|         if (uc <= p[1].QuadPart) {
 | |
|             p[1].QuadPart -= uc;
 | |
|             ullResult += 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult;
 | |
| }
 | |
| 
 | |
| LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d)
 | |
| {
 | |
|     ULARGE_INTEGER ua;
 | |
|     DWORD ub;
 | |
|     DWORD uc;
 | |
| 
 | |
|     /*  Compute the absolute values to avoid signed arithmetic problems */
 | |
|     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
 | |
|     ub = (DWORD)(b >= 0 ? b : -b);
 | |
|     uc = (DWORD)(c >= 0 ? c : -c);
 | |
|     BOOL bSign = (a < 0) ^ (b < 0);
 | |
| 
 | |
|     /*  Do long multiplication */
 | |
|     ULARGE_INTEGER p0;
 | |
|     DWORD p1;
 | |
|     p0.QuadPart  = UInt32x32To64(ua.LowPart, ub);
 | |
| 
 | |
|     if (ua.HighPart != 0) {
 | |
|         ULARGE_INTEGER x;
 | |
|         x.QuadPart     = UInt32x32To64(ua.HighPart, ub) + p0.HighPart;
 | |
|         p0.HighPart  = x.LowPart;
 | |
|         p1   = x.HighPart;
 | |
|     } else {
 | |
|         p1 = 0;
 | |
|     }
 | |
| 
 | |
|     if (d != 0) {
 | |
|         ULARGE_INTEGER ud0;
 | |
|         DWORD ud1;
 | |
| 
 | |
|         if (bSign) {
 | |
|             //
 | |
|             //  Cast d to LONGLONG first otherwise -0x80000000 sign extends
 | |
|             //  incorrectly
 | |
|             //
 | |
|             ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d);
 | |
|             if (d > 0) {
 | |
|                 /*  -d < 0 */
 | |
|                 ud1 = (DWORD)-1;
 | |
|             } else {
 | |
|                 ud1 = (DWORD)0;
 | |
|             }
 | |
|         } else {
 | |
|             ud0.QuadPart = (DWORDLONG)d;
 | |
|             if (d < 0) {
 | |
|                 ud1 = (DWORD)-1;
 | |
|             } else {
 | |
|                 ud1 = (DWORD)0;
 | |
|             }
 | |
|         }
 | |
|         /*  Now do extended addition */
 | |
|         ULARGE_INTEGER uliTotal;
 | |
| 
 | |
|         /*  Add ls DWORDs */
 | |
|         uliTotal.QuadPart  = (DWORDLONG)ud0.LowPart + p0.LowPart;
 | |
|         p0.LowPart       = uliTotal.LowPart;
 | |
| 
 | |
|         /*  Propagate carry */
 | |
|         uliTotal.LowPart   = uliTotal.HighPart;
 | |
|         uliTotal.HighPart  = 0;
 | |
| 
 | |
|         /*  Add 2nd most ls DWORDs */
 | |
|         uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart;
 | |
|         p0.HighPart      = uliTotal.LowPart;
 | |
| 
 | |
|         /*  Add MS DWORDLONGs - no carry expected */
 | |
|         p1 += ud1 + uliTotal.HighPart;
 | |
| 
 | |
|         /*  Now see if we got a sign change from the addition */
 | |
|         if ((LONG)p1 < 0) {
 | |
|             bSign = !bSign;
 | |
| 
 | |
|             /*  Negate the current value (ugh!) */
 | |
|             p0.QuadPart  = ~p0.QuadPart;
 | |
|             p1 = ~p1;
 | |
|             p0.QuadPart += 1;
 | |
|             p1 += (p0.QuadPart == 0);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*  Now for the division */
 | |
|     if (c < 0) {
 | |
|         bSign = !bSign;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /*  This will catch c == 0 and overflow */
 | |
|     if (uc <= p1) {
 | |
|         return bSign ? (LONGLONG)0x8000000000000000 :
 | |
|                        (LONGLONG)0x7FFFFFFFFFFFFFFF;
 | |
|     }
 | |
| 
 | |
|     /*  Do the division */
 | |
| 
 | |
|     /*  If the divisor is a DWORD then its simpler */
 | |
|     ULARGE_INTEGER uliDividend;
 | |
|     ULARGE_INTEGER uliResult;
 | |
|     DWORD dwDivisor = uc;
 | |
|     uliDividend.HighPart = p1;
 | |
|     uliDividend.LowPart = p0.HighPart;
 | |
|     /*  NOTE - this routine will take exceptions if
 | |
|         the result does not fit in a DWORD
 | |
|     */
 | |
|     if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
 | |
|         uliResult.HighPart = EnlargedUnsignedDivide(
 | |
|                                  uliDividend,
 | |
|                                  dwDivisor,
 | |
|                                  &p0.HighPart);
 | |
|     } else {
 | |
|         uliResult.HighPart = 0;
 | |
|     }
 | |
|     uliResult.LowPart = EnlargedUnsignedDivide(
 | |
|                              p0,
 | |
|                              dwDivisor,
 | |
|                              NULL);
 | |
|     return bSign ? -(LONGLONG)uliResult.QuadPart :
 | |
|                     (LONGLONG)uliResult.QuadPart;
 | |
| }
 |