oleaut32: Fixes for function variant:VarAnd.

This commit is contained in:
Benjamin Arai 2006-09-07 17:50:03 -07:00 committed by Alexandre Julliard
parent 97f85e497a
commit 3abb454c70
1 changed files with 170 additions and 62 deletions

View File

@ -2872,80 +2872,188 @@ HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
*/
HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
{
HRESULT rc = E_FAIL;
HRESULT hres = S_OK;
VARTYPE resvt = VT_EMPTY;
VARTYPE leftvt,rightvt;
VARTYPE rightExtraFlags,leftExtraFlags,ExtraFlags;
VARIANT varLeft, varRight;
VariantInit(&varLeft);
VariantInit(&varRight);
TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
(V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
leftvt = V_VT(left)&VT_TYPEMASK;
rightvt = V_VT(right)&VT_TYPEMASK;
leftExtraFlags = V_VT(left)&(~VT_TYPEMASK);
rightExtraFlags = V_VT(right)&(~VT_TYPEMASK);
V_VT(result) = VT_BOOL;
if (V_BOOL(left) && V_BOOL(right)) {
V_BOOL(result) = VARIANT_TRUE;
} else {
V_BOOL(result) = VARIANT_FALSE;
}
rc = S_OK;
if (leftExtraFlags != rightExtraFlags)
return DISP_E_BADVARTYPE;
ExtraFlags = leftExtraFlags;
} else {
/* Integers */
BOOL lOk = TRUE;
BOOL rOk = TRUE;
LONGLONG lVal = -1;
LONGLONG rVal = -1;
LONGLONG res = -1;
int resT = 0; /* Testing has shown I2 & I2 == I2, all else
becomes I4, even unsigned ints (incl. UI2) */
/* Native VarAnd always returns a error when using any extra
* flags or if the variant combination is I8 and INT.
*/
if ((leftvt == VT_I8 && rightvt == VT_INT) ||
(leftvt == VT_INT && rightvt == VT_I8) ||
ExtraFlags != 0)
return DISP_E_BADVARTYPE;
lOk = TRUE;
switch (V_VT(left)&VT_TYPEMASK) {
case VT_I1 : lVal = V_I1(left); resT=VT_I4; break;
case VT_I2 : lVal = V_I2(left); resT=VT_I2; break;
case VT_I4 :
case VT_INT : lVal = V_I4(left); resT=VT_I4; break;
case VT_UI1 : lVal = V_UI1(left); resT=VT_I4; break;
case VT_UI2 : lVal = V_UI2(left); resT=VT_I4; break;
case VT_UI4 :
case VT_UINT : lVal = V_UI4(left); resT=VT_I4; break;
case VT_BOOL : rVal = V_BOOL(left); resT=VT_I4; break;
default: lOk = FALSE;
}
/* Determine return type */
else if (leftvt == VT_I8 || rightvt == VT_I8)
resvt = VT_I8;
else if (leftvt == VT_I4 || rightvt == VT_I4 ||
leftvt == VT_UINT || rightvt == VT_UINT ||
leftvt == VT_INT || rightvt == VT_INT ||
leftvt == VT_UINT || rightvt == VT_UINT ||
leftvt == VT_R4 || rightvt == VT_R4 ||
leftvt == VT_R8 || rightvt == VT_R8 ||
leftvt == VT_CY || rightvt == VT_CY ||
leftvt == VT_DATE || rightvt == VT_DATE ||
leftvt == VT_I1 || rightvt == VT_I1 ||
leftvt == VT_UI2 || rightvt == VT_UI2 ||
leftvt == VT_UI4 || rightvt == VT_UI4 ||
leftvt == VT_UI8 || rightvt == VT_UI8 ||
leftvt == VT_DECIMAL || rightvt == VT_DECIMAL)
resvt = VT_I4;
else if (leftvt == VT_UI1 || rightvt == VT_UI1 ||
leftvt == VT_I2 || rightvt == VT_I2 ||
leftvt == VT_EMPTY || rightvt == VT_EMPTY)
if ((leftvt == VT_NULL && rightvt == VT_UI1) ||
(leftvt == VT_UI1 && rightvt == VT_NULL) ||
(leftvt == VT_UI1 && rightvt == VT_UI1))
resvt = VT_UI1;
else
resvt = VT_I2;
else if (leftvt == VT_BOOL || rightvt == VT_BOOL ||
(leftvt == VT_BSTR && rightvt == VT_BSTR))
resvt = VT_BOOL;
else if (leftvt == VT_NULL || rightvt == VT_NULL ||
leftvt == VT_BSTR || rightvt == VT_BSTR)
resvt = VT_NULL;
else
return DISP_E_BADVARTYPE;
rOk = TRUE;
switch (V_VT(right)&VT_TYPEMASK) {
case VT_I1 : rVal = V_I1(right); resT=VT_I4; break;
case VT_I2 : rVal = V_I2(right); resT=max(VT_I2, resT); break;
case VT_I4 :
case VT_INT : rVal = V_I4(right); resT=VT_I4; break;
case VT_UI1 : rVal = V_UI1(right); resT=VT_I4; break;
case VT_UI2 : rVal = V_UI2(right); resT=VT_I4; break;
case VT_UI4 :
case VT_UINT : rVal = V_UI4(right); resT=VT_I4; break;
case VT_BOOL : rVal = V_BOOL(right); resT=VT_I4; break;
default: rOk = FALSE;
}
if (lOk && rOk) {
res = (lVal & rVal);
V_VT(result) = resT;
switch (resT) {
case VT_I2 : V_I2(result) = res; break;
case VT_I4 : V_I4(result) = res; break;
default:
FIXME("Unexpected result variant type %x\n", resT);
V_I4(result) = res;
if (leftvt == VT_NULL || rightvt == VT_NULL)
{
/*
* Special cases for when left variant is VT_NULL
* (NULL & 0 = NULL, NULL & value = value)
*/
if (leftvt == VT_NULL)
{
VARIANT_BOOL b;
switch(rightvt)
{
case VT_I1: if (V_I1(right)) resvt = VT_NULL; break;
case VT_UI1: if (V_UI1(right)) resvt = VT_NULL; break;
case VT_I2: if (V_I2(right)) resvt = VT_NULL; break;
case VT_UI2: if (V_UI2(right)) resvt = VT_NULL; break;
case VT_I4: if (V_I4(right)) resvt = VT_NULL; break;
case VT_UI4: if (V_UI4(right)) resvt = VT_NULL; break;
case VT_I8: if (V_I8(right)) resvt = VT_NULL; break;
case VT_UI8: if (V_UI8(right)) resvt = VT_NULL; break;
case VT_INT: if (V_INT(right)) resvt = VT_NULL; break;
case VT_UINT: if (V_UINT(right)) resvt = VT_NULL; break;
case VT_BOOL: if (V_BOOL(right)) resvt = VT_NULL; break;
case VT_R4: if (V_R4(right)) resvt = VT_NULL; break;
case VT_R8: if (V_R8(right)) resvt = VT_NULL; break;
case VT_CY:
if(V_CY(right).int64)
resvt = VT_NULL;
break;
case VT_DECIMAL:
if (DEC_HI32(&V_DECIMAL(right)) ||
DEC_LO64(&V_DECIMAL(right)))
resvt = VT_NULL;
break;
case VT_BSTR:
hres = VarBoolFromStr(V_BSTR(right),
LOCALE_USER_DEFAULT, VAR_LOCALBOOL, &b);
if (FAILED(hres))
return hres;
else if (b)
V_VT(result) = VT_NULL;
else
{
V_VT(result) = VT_BOOL;
V_BOOL(result) = b;
}
goto VarAnd_Exit;
}
rc = S_OK;
} else {
FIXME("VarAnd stub\n");
}
V_VT(result) = resvt;
goto VarAnd_Exit;
}
TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result),
debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result));
return rc;
hres = VariantCopy(&varLeft, left);
if (FAILED(hres)) goto VarAnd_Exit;
hres = VariantCopy(&varRight, right);
if (FAILED(hres)) goto VarAnd_Exit;
if (resvt == VT_I4 && V_VT(&varLeft) == VT_UI4)
V_VT(&varLeft) = VT_I4; /* Don't overflow */
else
{
double d;
if (V_VT(&varLeft) == VT_BSTR &&
FAILED(VarR8FromStr(V_BSTR(&varLeft),
LOCALE_USER_DEFAULT, 0, &d)))
hres = VariantChangeType(&varLeft,&varLeft,
VARIANT_LOCALBOOL, VT_BOOL);
if (SUCCEEDED(hres) && V_VT(&varLeft) != resvt)
hres = VariantChangeType(&varLeft,&varLeft,0,resvt);
if (FAILED(hres)) goto VarAnd_Exit;
}
if (resvt == VT_I4 && V_VT(&varRight) == VT_UI4)
V_VT(&varRight) = VT_I4; /* Don't overflow */
else
{
double d;
if (V_VT(&varRight) == VT_BSTR &&
FAILED(VarR8FromStr(V_BSTR(&varRight),
LOCALE_USER_DEFAULT, 0, &d)))
hres = VariantChangeType(&varRight, &varRight,
VARIANT_LOCALBOOL, VT_BOOL);
if (SUCCEEDED(hres) && V_VT(&varRight) != resvt)
hres = VariantChangeType(&varRight, &varRight, 0, resvt);
if (FAILED(hres)) goto VarAnd_Exit;
}
V_VT(result) = resvt;
switch(resvt)
{
case VT_I8:
V_I8(result) = V_I8(&varLeft) & V_I8(&varRight);
break;
case VT_I4:
V_I4(result) = V_I4(&varLeft) & V_I4(&varRight);
break;
case VT_I2:
V_I2(result) = V_I2(&varLeft) & V_I2(&varRight);
break;
case VT_UI1:
V_UI1(result) = V_UI1(&varLeft) & V_UI1(&varRight);
break;
case VT_BOOL:
V_BOOL(result) = V_BOOL(&varLeft) & V_BOOL(&varRight);
break;
default:
FIXME("Couldn't bitwise AND variant types %d,%d\n",
leftvt,rightvt);
}
VarAnd_Exit:
VariantClear(&varLeft);
VariantClear(&varRight);
return hres;
}
/**********************************************************************