oleaut32 1/2: Fixes for function variant:VarIdiv

Benjamin Arai me at benjaminarai.com
Wed Sep 6 20:26:07 CDT 2006


Hi,

The two patches add a conformance test and fixes to the variant
function VarIdiv.  The original implementation crashed the conformance
test due to improper handling of certain variant types.  The
conformance test (2/2) exposes problems with the error code handling
and unhandled variant types, the fix (1/2) addresses all of the
issues.

---
 dlls/oleaut32/variant.c |  132 ++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 112 insertions(+), 20 deletions(-)

Copyright: Google
License: LGPL

-- 
Benjamin Arai
http://www.benjaminarai.com
-------------- next part --------------

diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c
index c51533d..a917f71 100644
--- a/dlls/oleaut32/variant.c
+++ b/dlls/oleaut32/variant.c
@@ -4991,33 +4991,125 @@ HRESULT WINAPI VarRound(LPVARIANT pVarIn
  */
 HRESULT WINAPI VarIdiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
 {
-    VARIANT lv, rv;
-    HRESULT hr;
-    
+    HRESULT hres = S_OK;
+    VARTYPE resvt = VT_EMPTY;
+    VARTYPE leftvt,rightvt;
+    VARTYPE rightExtraFlags,leftExtraFlags,ExtraFlags;
+    VARIANT lv,rv;
+
+    leftvt = V_VT(left)&VT_TYPEMASK;
+    rightvt = V_VT(right)&VT_TYPEMASK;
+    leftExtraFlags = V_VT(left)&(~VT_TYPEMASK);
+    rightExtraFlags = V_VT(right)&(~VT_TYPEMASK);
+
+    if (leftExtraFlags != rightExtraFlags)
+        return DISP_E_BADVARTYPE;
+    ExtraFlags = leftExtraFlags;
+
+    TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
+          debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
+
+    /* All extra flags produce errors */
+    if (ExtraFlags == (VT_ARRAY|VT_BYREF) ||
+        ExtraFlags == (VT_BYREF) ||
+        ExtraFlags == (VT_ARRAY) )
+    {
+        if ((leftvt >= VT_I2 && leftvt <= VT_BSTR) ||
+            (leftvt >= VT_ERROR && leftvt <= VT_VARIANT) ||
+            (leftvt >= VT_I1 && leftvt <= VT_UINT) ||
+            leftvt == VT_DECIMAL)
+            return DISP_E_TYPEMISMATCH;
+        else
+            return DISP_E_BADVARTYPE;
+    }
+    else if (ExtraFlags)
+        return DISP_E_BADVARTYPE;
+    else if (leftvt == VT_VARIANT || leftvt == VT_ERROR)
+        return DISP_E_TYPEMISMATCH;
+    /* Handling for all remaining errors and return types */
+    /*  The following flags/types are invalid for left variant */
+    else if (!((leftvt <= VT_LPWSTR) && leftvt != (VARTYPE)15 &&
+        (leftvt < VT_VOID || leftvt > VT_LPWSTR)))
+        return DISP_E_BADVARTYPE;
+    /*  The following flags/types are invalid for right variant */
+    else if (!((rightvt <= VT_LPWSTR) && rightvt != (VARTYPE)15 &&
+        (rightvt < VT_VOID || rightvt > VT_LPWSTR)))
+        return DISP_E_BADVARTYPE;
+    else if (rightvt == VT_VARIANT || rightvt == VT_ERROR ||
+        (leftvt == VT_INT && rightvt == VT_I8) ||
+        (leftvt == VT_I8 && rightvt == VT_INT))
+        return DISP_E_TYPEMISMATCH;
+    else if (leftvt == VT_NULL || rightvt == VT_NULL)
+        resvt = VT_NULL;
+    else if (rightvt == VT_EMPTY)
+        return DISP_E_DIVBYZERO;
+    else if ((leftvt == VT_EMPTY || leftvt == VT_I2 ||
+        leftvt == VT_I4 || leftvt == VT_R4 ||
+        leftvt == VT_R8 || leftvt == VT_CY ||
+        leftvt == VT_DATE || leftvt == VT_BSTR ||
+        leftvt == VT_BOOL || leftvt == VT_DECIMAL ||
+        (leftvt >= VT_I1 && leftvt <= VT_UINT)) &&
+        (rightvt == VT_EMPTY || rightvt == VT_I2 ||
+        rightvt == VT_I4 || rightvt == VT_R4 ||
+        rightvt == VT_R8 || rightvt == VT_CY ||
+        rightvt == VT_DATE || rightvt == VT_BSTR ||
+        rightvt == VT_BOOL || rightvt == VT_DECIMAL ||
+        (rightvt >= VT_I1 && rightvt <= VT_UINT)))
+    {
+        if (leftvt == VT_UI1 && rightvt == VT_UI1)
+            resvt = VT_UI1;
+        else if (leftvt == VT_I8 || rightvt == VT_I8)
+            resvt = VT_I8;
+        else if ((leftvt == VT_EMPTY || leftvt == VT_UI1 ||
+            leftvt == VT_BOOL || leftvt == VT_I2) &&
+            (rightvt == VT_UI1 || rightvt == VT_BOOL ||
+            rightvt == VT_I2))
+            resvt = VT_I2;
+        else
+            resvt = VT_I4;
+    }
+
     VariantInit(&lv);
     VariantInit(&rv);
 
-    if ((V_VT(left) == VT_NULL) || (V_VT(right) == VT_NULL)) {
-        hr = VariantChangeType(result, result, 0, VT_NULL);
-        if (FAILED(hr)) {
-            /* This should never happen */
-            FIXME("Failed to convert return value to VT_NULL.\n");
-            return hr;
-        }
-        return S_OK;
+    /* coerce to the result type */
+    hres = VariantChangeType(&lv, left, 0, resvt);
+    if (hres != S_OK)
+    {
+        VariantClear(&lv);
+        VariantClear(&rv);
+        return hres;
     }
-
-    hr = VariantChangeType(&lv, left, 0, VT_I4);
-    if (FAILED(hr)) {
-	return hr;
+    hres = VariantChangeType(&rv, right, 0, resvt);
+    if (hres != S_OK)
+    {
+        VariantClear(&lv);
+        VariantClear(&rv);
+        return hres;
     }
-    hr = VariantChangeType(&rv, right, 0, VT_I4);
-    if (FAILED(hr)) {
-	return hr;
+
+    /* do the math */
+    V_VT(result) = resvt;
+    switch (resvt)
+    {
+    case VT_UI1:
+    V_UI1(result) = V_UI1(&lv) / V_UI1(&rv);
+    break;
+    case VT_I2:
+    V_I2(result) = V_I2(&lv) / V_I2(&rv);
+    break;
+    case VT_I4:
+    V_I4(result) = V_I4(&lv) / V_I4(&rv);
+    break;
+    case VT_I8:
+    V_I8(result) = V_I8(&lv) / V_I8(&rv);
+    break;
     }
 
-    hr = VarDiv(&lv, &rv, result);
-    return hr;
+    VariantClear(&lv);
+    VariantClear(&rv);
+
+    return hres;
 }
 
 
-- 
1.4.0


More information about the wine-patches mailing list