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; | ||
|  | } |