Module: wine Branch: master Commit: ec218b42181709c26cbb076761c345826f2b6353 URL: http://source.winehq.org/git/wine.git/?a=commit;h=ec218b42181709c26cbb076761...
Author: Sebastian Lackner sebastian@fds-team.de Date: Mon Jul 7 22:13:59 2014 +0200
oleaut32: Decrease accuracy if scaling is not possible in VarDecAdd.
---
dlls/oleaut32/tests/vartype.c | 10 +++---- dlls/oleaut32/vartype.c | 70 +++++++++++++++++++++++++++++++++---------- 2 files changed, 59 insertions(+), 21 deletions(-)
diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c index 8ca3f14..026149a 100644 --- a/dlls/oleaut32/tests/vartype.c +++ b/dlls/oleaut32/tests/vartype.c @@ -4419,7 +4419,7 @@ static void test_VarDecAdd(void) todo_wine EXPECTDEC64(0,0,0x2d3c8750,0xbd670354,0xb0000000);
SETDEC(l,3,128,0,123456); SETDEC64(r,0,0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF); - MATH2(VarDecAdd); todo_wine EXPECTDEC64(0,0,-1,0xFFFFFFFF,0xFFFFFF84); + MATH2(VarDecAdd); EXPECTDEC64(0,0,-1,0xFFFFFFFF,0xFFFFFF84);
SETDEC(l,3,0,0,123456); SETDEC64(r,0,0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF); MATH2(VarDecAdd); ok(hres == DISP_E_OVERFLOW,"Expected overflow, got (%d,%d,%d,(%8x,%8x)x) hres 0x%08x\n", @@ -4434,13 +4434,13 @@ static void test_VarDecAdd(void) S(U(out)).scale, S(U(out)).sign, out.Hi32, S1(U1(out)).Mid32, S1(U1(out)).Lo32, hres);
SETDEC(l,6,0,0,123456); SETDEC64(r,0,0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF); - MATH2(VarDecAdd); todo_wine EXPECTDEC64(0,0,-1,0xFFFFFFFF,0xFFFFFFFF); + MATH2(VarDecAdd); EXPECTDEC64(0,0,-1,0xFFFFFFFF,0xFFFFFFFF);
SETDEC(l,3,128,0,123456); SETDEC64(r,0,0,0x19999999,0x99999999,0x99999999); - MATH2(VarDecAdd); todo_wine EXPECTDEC64(1,0,-1,0xFFFFFFFF,0xFFFFFB27); + MATH2(VarDecAdd); EXPECTDEC64(1,0,-1,0xFFFFFFFF,0xFFFFFB27);
SETDEC(l,3,128,0,123567); SETDEC64(r,0,0,0x19999999,0x99999999,0x99999999); - MATH2(VarDecAdd); todo_wine EXPECTDEC64(1,0,-1,0xFFFFFFFF,0xFFFFFB26); + MATH2(VarDecAdd); EXPECTDEC64(1,0,-1,0xFFFFFFFF,0xFFFFFB26);
/* Promotes to the highest scale, so here the results are in the scale of 2 */ SETDEC(l,2,0,0,0); SETDEC(r,0,0,0,0); MATH2(VarDecAdd); EXPECTDEC(2,0,0,0); @@ -4663,7 +4663,7 @@ static void test_VarDecCmp(void) SETDEC(out,0,DECIMAL_NEG,-1,-1); SETDEC(l,0,DECIMAL_NEG,-1,-1); MATH1(VarDecCmp); EXPECT_EQ;
SETDEC(l,3,0,0,123456); SETDEC64(out,0,0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF); - MATH1(VarDecCmp); todo_wine EXPECT_LT; + MATH1(VarDecCmp); EXPECT_LT; }
static void test_VarDecCmpR8(void) diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c index 4d067e0..e9b45ff 100644 --- a/dlls/oleaut32/vartype.c +++ b/dlls/oleaut32/vartype.c @@ -4164,6 +4164,8 @@ static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest); static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest); static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to); static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to); +static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor); +static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
/************************************************************************ * VarDecFromR4 (OLEAUT32.193) @@ -4439,12 +4441,13 @@ HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) /* Make two DECIMALS the same scale; used by math functions below */ static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, const DECIMAL** ppDecRight, - DECIMAL* pDecOut) + DECIMAL pDecOut[2]) { static DECIMAL scaleFactor; + unsigned char remainder; DECIMAL decTemp; + VARIANT_DI di; int scaleAmount, i; - HRESULT hRet = S_OK;
if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) return E_INVALIDARG; @@ -4459,27 +4462,62 @@ static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, if (scaleAmount > 0) { decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ - *ppDecRight = pDecOut; + *ppDecRight = &pDecOut[0]; } else { decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ - *ppDecLeft = pDecOut; - i = scaleAmount = -scaleAmount; + *ppDecLeft = &pDecOut[0]; + i = -scaleAmount; }
- if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE) - return DISP_E_OVERFLOW; /* Can't scale up */ + /* Multiply up the value to be scaled by the correct amount (if possible) */ + while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0]))) + { + decTemp = pDecOut[0]; + i--; + }
- /* Multiply up the value to be scaled by the correct amount */ - while (SUCCEEDED(hRet) && i--) + if (!i) { - /* Note we are multiplying by a value with a scale of 0, so we don't recurse */ - hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut); - decTemp = *pDecOut; + DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount); + return S_OK; /* Same scale */ } - DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */ - return hRet; + + /* Scaling further not possible, reduce accuracy of other argument */ + pDecOut[0] = decTemp; + if (scaleAmount > 0) + { + DEC_SCALE(&pDecOut[0]) += scaleAmount - i; + VARIANT_DIFromDec(*ppDecLeft, &di); + *ppDecLeft = &pDecOut[1]; + } + else + { + DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i; + VARIANT_DIFromDec(*ppDecRight, &di); + *ppDecRight = &pDecOut[1]; + } + + di.scale -= i; + remainder = 0; + while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD))) + { + remainder = VARIANT_int_divbychar(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD), 10); + if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder); + } + + /* round up the result - native oleaut32 does this */ + if (remainder >= 5) { + for (remainder = 1, i = 0; i < sizeof(di.bitsnum)/sizeof(DWORD) && remainder; i++) { + ULONGLONG digit = di.bitsnum[i] + 1; + remainder = (digit > 0xFFFFFFFF) ? 1 : 0; + di.bitsnum[i] = digit & 0xFFFFFFFF; + } + } + + VARIANT_DecFromDI(&di, &pDecOut[1]); + return S_OK; }
/* Add two unsigned 32 bit values with overflow */ @@ -4554,9 +4592,9 @@ static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRig HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) { HRESULT hRet; - DECIMAL scaled; + DECIMAL scaled[2];
- hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled); + hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
if (SUCCEEDED(hRet)) {