Sebastian Lackner : oleaut32: Decrease accuracy if scaling is not possible in VarDecAdd.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Jul 9 14:35:20 CDT 2014


Module: wine
Branch: master
Commit: ec218b42181709c26cbb076761c345826f2b6353
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ec218b42181709c26cbb076761c345826f2b6353

Author: Sebastian Lackner <sebastian at 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))
   {




More information about the wine-cvs mailing list