summaryrefslogtreecommitdiff
path: root/third_party/BaseClasses/arithutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/BaseClasses/arithutil.cpp')
-rw-r--r--third_party/BaseClasses/arithutil.cpp360
1 files changed, 360 insertions, 0 deletions
diff --git a/third_party/BaseClasses/arithutil.cpp b/third_party/BaseClasses/arithutil.cpp
new file mode 100644
index 00000000..cd0d1271
--- /dev/null
+++ b/third_party/BaseClasses/arithutil.cpp
@@ -0,0 +1,360 @@
+//------------------------------------------------------------------------------
+// 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;
+}