You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
10 KiB
379 lines
10 KiB
//=================================================
|
|
//
|
|
// File : CVariant.cxx
|
|
//
|
|
// purpose : implementation of a very usefull VARIANT wrapper class
|
|
//
|
|
//=================================================
|
|
|
|
|
|
#include "headers.h"
|
|
|
|
#pragma MARK_DATA(__FILE__)
|
|
#pragma MARK_CODE(__FILE__)
|
|
#pragma MARK_CONST(__FILE__)
|
|
#include "utils.hxx"
|
|
|
|
#ifndef X_DISPEX_H_
|
|
#define X_DISPEX_H_
|
|
#include <dispex.h>
|
|
#endif
|
|
|
|
|
|
|
|
// IEEE format specifies these...
|
|
// +Infinity: 7FF00000 00000000
|
|
// -Infinity: FFF00000 00000000
|
|
// NAN: 7FF***** ********
|
|
// NAN: FFF***** ********
|
|
|
|
// We also test for these, because the MSVC 1.52 CRT produces them for things
|
|
// like log(0)...
|
|
// +Infinity: 7FEFFFFF FFFFFFFF
|
|
// -Infinity: FFEFFFFF FFFFFFFF
|
|
|
|
|
|
// returns true for non-infinite nans.
|
|
int isNAN(double dbl)
|
|
{
|
|
union
|
|
{
|
|
USHORT rgw[4];
|
|
ULONG rglu[2];
|
|
double dbl;
|
|
} v;
|
|
|
|
v.dbl = dbl;
|
|
|
|
#ifdef BIG_ENDIAN
|
|
return 0 == (~v.rgw[0] & 0x7FF0) &&
|
|
((v.rgw[0] & 0x000F) || v.rgw[1] || v.rglu[1]);
|
|
#else
|
|
return 0 == (~v.rgw[3] & 0x7FF0) &&
|
|
((v.rgw[3] & 0x000F) || v.rgw[2] || v.rglu[0]);
|
|
#endif
|
|
}
|
|
|
|
|
|
// returns false for infinities and nans.
|
|
int isFinite(double dbl)
|
|
{
|
|
union
|
|
{
|
|
USHORT rgw[4];
|
|
ULONG rglu[2];
|
|
double dbl;
|
|
} v;
|
|
|
|
v.dbl = dbl;
|
|
|
|
#ifdef BIG_ENDIAN
|
|
return (~v.rgw[0] & 0x7FE0) ||
|
|
0 == (v.rgw[0] & 0x0010) &&
|
|
(~v.rglu[1] || ~v.rgw[1] || (~v.rgw[0] & 0x000F));
|
|
#else
|
|
return (~v.rgw[3] & 0x7FE0) ||
|
|
0 == (v.rgw[3] & 0x0010) &&
|
|
(~v.rglu[0] || ~v.rgw[2] || (~v.rgw[3] & 0x000F));
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: VARIANTARGChangeTypeSpecial
|
|
//
|
|
// Synopsis: Helper.
|
|
// Converts a VARIANT of arbitrary type to a VARIANT of type VT,
|
|
// using browswer specific conversion rules, which may differ from
|
|
// standard OLE Automation conversion rules (usually because
|
|
// Netscape does something wierd).
|
|
//
|
|
// This was pulled out of VARIANTARGToCVar because its also called
|
|
// from CheckBox databinding.
|
|
//
|
|
// Arguments: [pVArgDest] -- Destination VARIANT (should already be init'd).
|
|
// [vt] -- Type to convert to.
|
|
// [pvarg] -- Variant to convert.
|
|
// [pv] -- Location to place C-language variable.
|
|
//
|
|
// Modifies: [pv].
|
|
//
|
|
// Returns: HRESULT.
|
|
//
|
|
// History: 1-7-96 cfranks pulled out from VARIANTARGToCVar.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
VariantChangeTypeSpecial(VARIANT *pVArgDest,
|
|
VARIANT *pvarg,
|
|
VARTYPE vt,
|
|
IServiceProvider *pSrvProvider,
|
|
WORD wFlags)
|
|
{
|
|
HRESULT hr;
|
|
IVariantChangeType *pVarChangeType = NULL;
|
|
|
|
if (pSrvProvider)
|
|
{
|
|
hr = pSrvProvider->QueryService(SID_VariantConversion,
|
|
IID_IVariantChangeType,
|
|
(void **)&pVarChangeType);
|
|
if (hr)
|
|
goto OldWay;
|
|
|
|
// Use script engine conversion routine.
|
|
hr = pVarChangeType->ChangeType(pVArgDest, pvarg, 0, vt);
|
|
if (!hr)
|
|
goto Cleanup; // ChangeType suceeded we're done...
|
|
}
|
|
|
|
// Fall back to our tried & trusted type coercions
|
|
OldWay:
|
|
|
|
hr = S_OK;
|
|
|
|
if (vt == VT_BSTR && V_VT(pvarg) == VT_NULL)
|
|
{
|
|
// Converting a NULL to BSTR
|
|
V_VT(pVArgDest) = VT_BSTR;
|
|
V_BSTR(pVArgDest) = SysAllocString( L"null");
|
|
if (! V_BSTR(pVArgDest) )
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
|
}
|
|
else if (vt == VT_BSTR && V_VT(pvarg) == VT_EMPTY)
|
|
{
|
|
// Converting "undefined" to BSTR
|
|
V_VT(pVArgDest) = VT_BSTR;
|
|
V_BSTR(pVArgDest) = SysAllocString( L"undefined");
|
|
if (! V_BSTR(pVArgDest) )
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
|
}
|
|
else if (vt == VT_BOOL && V_VT(pvarg) == VT_BSTR)
|
|
{
|
|
// Converting from BSTR to BOOL
|
|
// To match Navigator compatibility empty strings implies false when
|
|
// assigned to a boolean type any other string implies true.
|
|
V_VT(pVArgDest) = VT_BOOL;
|
|
V_BOOL(pVArgDest) = SysStringLen(V_BSTR(pvarg)) == 0 ? VB_FALSE : VB_TRUE;
|
|
goto Cleanup;
|
|
}
|
|
else if ( V_VT(pvarg) == VT_BOOL && vt == VT_BSTR )
|
|
{
|
|
// Converting from BOOL to BSTR
|
|
// To match Nav we either get "true" or "false"
|
|
V_VT(pVArgDest) = VT_BSTR;
|
|
V_BSTR(pVArgDest) = SysAllocString( V_BOOL(pvarg) == VB_TRUE ? L"true" : L"false");
|
|
if (! V_BSTR(pVArgDest) )
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
goto Cleanup;
|
|
}
|
|
// If we're converting R4 or R8 to a string then we need special handling to
|
|
// map Nan and +/-Inf.
|
|
else if (vt == VT_BSTR && (V_VT(pvarg) == VT_R8 || V_VT(pvarg) == VT_R4))
|
|
{
|
|
double dblValue = V_VT(pvarg) == VT_R8 ? V_R8(pvarg) : (double)(V_R4(pvarg));
|
|
|
|
// Infinity or NAN?
|
|
if (!isFinite(dblValue))
|
|
{
|
|
if (isNAN(dblValue))
|
|
{
|
|
// NAN
|
|
V_BSTR(pVArgDest) = SysAllocString(L"NaN");
|
|
if (! V_BSTR(pVArgDest))
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
// Infinity
|
|
V_BSTR(pVArgDest) = SysAllocString((dblValue < 0) ? L"-Infinity" : L"Infinity" );
|
|
if (! V_BSTR(pVArgDest))
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
goto DefaultConvert;
|
|
|
|
|
|
// Any error from allocating string?
|
|
if (hr)
|
|
goto Cleanup;
|
|
|
|
V_VT(pVArgDest) = vt;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
DefaultConvert:
|
|
//
|
|
// Default VariantChangeTypeEx.
|
|
//
|
|
|
|
// VARIANT_NOUSEROVERRIDE flag is undocumented flag that tells OLEAUT to convert to the lcid
|
|
// given. Without it the conversion is done to user localeid
|
|
hr = VariantChangeTypeEx(pVArgDest,
|
|
pvarg,
|
|
LCID_SCRIPTING,
|
|
wFlags|VARIANT_NOUSEROVERRIDE,
|
|
vt);
|
|
|
|
|
|
if (hr == DISP_E_TYPEMISMATCH )
|
|
{
|
|
if ( V_VT(pvarg) == VT_NULL )
|
|
{
|
|
hr = S_OK;
|
|
switch ( vt )
|
|
{
|
|
case VT_BOOL:
|
|
V_BOOL(pVArgDest) = VB_FALSE;
|
|
V_VT(pVArgDest) = VT_BOOL;
|
|
break;
|
|
|
|
// For NS compatability - NS treats NULL args as 0
|
|
default:
|
|
V_I4(pVArgDest)=0;
|
|
break;
|
|
}
|
|
}
|
|
else if (V_VT(pvarg) == VT_DISPATCH )
|
|
{
|
|
// Nav compatability - return the string [object] or null
|
|
V_VT(pVArgDest) = VT_BSTR;
|
|
V_BSTR(pVArgDest) = SysAllocString ( (V_DISPATCH(pvarg)) ? L"[object]" : L"null");
|
|
if (! V_BSTR(pVArgDest) )
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
else if ( V_VT(pvarg) == VT_BSTR && V_BSTRREF(pvarg) &&
|
|
( (V_BSTR(pvarg))[0] == _T('\0')) && ( vt == VT_I4 || vt == VT_I2 || vt == VT_UI2 || vt == VT_UI4 || vt == VT_I8 ||
|
|
vt == VT_UI8 || vt == VT_INT || vt == VT_UINT ) )
|
|
{
|
|
// Converting empty string to integer => Zero
|
|
hr = S_OK;
|
|
V_VT(pVArgDest) = vt;
|
|
V_I4(pVArgDest) = 0;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else if (hr == DISP_E_OVERFLOW && vt == VT_I4 && (V_VT(pvarg) == VT_R8 || V_VT(pvarg) == VT_R4))
|
|
{
|
|
// Nav compatability - return MAXLONG on overflow
|
|
V_VT(pVArgDest) = VT_I4;
|
|
V_I4(pVArgDest) = MAXLONG;
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseInterface(pVarChangeType);
|
|
|
|
return hr ;
|
|
}
|
|
|
|
|
|
|
|
//+--------------------------------------------------------
|
|
//
|
|
// Method : CVariant::CoerceVariantArg
|
|
//
|
|
// Synopsis : Coerce current variant into itself or
|
|
// Coerce pArgFrom into this instance from anyvariant
|
|
// to a given type
|
|
//
|
|
//+--------------------------------------------------------
|
|
|
|
HRESULT CVariant::CoerceVariantArg ( VARIANT *pArgFrom, WORD wCoerceToType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
VARIANT *pvar;
|
|
|
|
if( V_VT(pArgFrom) == (VT_BYREF | VT_VARIANT) )
|
|
pvar = V_VARIANTREF(pArgFrom);
|
|
else
|
|
pvar = pArgFrom;
|
|
|
|
if ( !(pvar->vt == VT_EMPTY || pvar->vt == VT_ERROR ) )
|
|
{
|
|
hr = VariantChangeTypeSpecial ( (VARIANT *)this,
|
|
pvar,
|
|
wCoerceToType );
|
|
}
|
|
else
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CVariant::CoerceVariantArg (WORD wCoerceToType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( !(vt == VT_EMPTY || vt == VT_ERROR ) )
|
|
{
|
|
hr = VariantChangeTypeSpecial ( (VARIANT *)this,
|
|
(VARIANT *)this, wCoerceToType );
|
|
}
|
|
else
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------
|
|
//
|
|
// Method : CVariant::CoerceNumericToI4
|
|
//
|
|
// Synopsis : Coerce any numeric (VT_I* or VT_UI*) into a
|
|
// VT_I4 in this instance
|
|
//
|
|
//+--------------------------------------------------------
|
|
BOOL CVariant::CoerceNumericToI4 ()
|
|
{
|
|
switch (vt)
|
|
{
|
|
case VT_I1:
|
|
case VT_UI1:
|
|
lVal = 0x000000FF & (DWORD)bVal;
|
|
break;
|
|
|
|
case VT_UI2:
|
|
case VT_I2:
|
|
lVal = 0x0000FFFF & (DWORD)iVal;
|
|
break;
|
|
|
|
case VT_UI4:
|
|
case VT_I4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
break;
|
|
|
|
case VT_R8:
|
|
lVal = (LONG)dblVal;
|
|
break;
|
|
|
|
case VT_R4:
|
|
lVal = (LONG)fltVal;
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
vt = VT_I4;
|
|
return TRUE;
|
|
}
|