void UnoConversionUtilities::variantToAny()

in main/extensions/source/ole/unoconversionutilities.hxx [304:611]


void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype,  sal_Bool bReduceValueRange /* = sal_True */)
{
    try
    {
        HRESULT hr;
        bool bFail = false;
        bool bCannotConvert = false;
        CComVariant var;
        
        // There is no need to support indirect values, since they're not supported by UNO
        if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pArg)))) // remove VT_BYREF
            throw BridgeRuntimeError(
                OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
                      "VariantCopyInd failed for reason : ") + OUString::valueOf(hr));
        bool bHandled = convertValueObject( & var, rAny);
        if( bHandled)
            OSL_ENSURE(  rAny.getValueType() == ptype, "type in Value Object must match the type parameter");	
        
        if( ! bHandled)
        {
            // convert into a variant type that is the equivalent to the type
            // the sequence expects. Thus variantToAny produces the correct type
            // E.g. An Array object contains VT_I4 and the sequence expects shorts
            // than the vartype must be changed. The reason is, you can't specify the 
            // type in JavaScript and the script engine determines the type being used.
            switch( ptype.getTypeClass())
            {
            case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
                if( var.vt == VT_BSTR)
                {
                    if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
                        rAny.setValue( (void*)V_BSTR( &var), ptype);
					else if (hr == DISP_E_TYPEMISMATCH)
						bCannotConvert = true;
                    else
                        bFail = true;
                }
				else
				{
					if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
						rAny.setValue((void*) & var.iVal, ptype);
					else if (hr == DISP_E_TYPEMISMATCH)
						bCannotConvert = true;
					else
						bFail = true;
                }
                break;
            case TypeClass_INTERFACE: // could also be an IUnknown
            case TypeClass_STRUCT:	
            {                    
                rAny = createOleObjectWrapper( & var, ptype);
                break;
            }
            case TypeClass_ENUM: 
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
                    rAny.setValue((void*) & var.lVal, ptype);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            case TypeClass_SEQUENCE: 
                // There are different ways of receiving a sequence:
                // 1: JScript, VARTYPE: VT_DISPATCH
                // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
                //		a VT_ARRAY|  <type>
                // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF
                if( pArg->vt == VT_DISPATCH)
                {
                    dispatchExObject2Sequence( pArg, rAny, ptype);
                }
                else
                {
                    if ((var.vt & VT_ARRAY) != 0)
                    {
                        VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
                        Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
                        Reference<XTypeConverter> conv = getTypeConverter();
                        if (conv.is())
                        {
                            try 
                            {
                                Any anySeq = makeAny(unoSeq);
                                Any convAny = conv->convertTo(anySeq, ptype);
                                rAny = convAny;
                            }
                            catch (IllegalArgumentException& e)
                            {
                                throw BridgeRuntimeError(
                                    OUSTR("[automation bridge]com.sun.star.lang.IllegalArgumentException "
                                          "in UnoConversionUtilities<T>::variantToAny! Message: ") +
                                    e.Message);
                            }
                            catch (CannotConvertException& e)
                            {
                                throw BridgeRuntimeError(
                                    OUSTR("[automation bridge]com.sun.star.script.CannotConvertException "
                                          "in UnoConversionUtilities<T>::variantToAny! Message: ") +
                                    e.Message);
                            }
                        }
                    }
                }
                break; 
            case TypeClass_VOID: 
                rAny.setValue(NULL,Type());
                break;
            case TypeClass_ANY:		//  Any 
                // There could be a JScript Array that needs special handling
                // If an Any is expected and this Any must contain a Sequence
                // then we cannot figure out what element type is required.
                // Therefore we convert to Sequence< Any >
                if( pArg->vt == VT_DISPATCH && 	isJScriptArray( pArg))
                {
                    dispatchExObject2Sequence( pArg, rAny,
                                               getCppuType((Sequence<Any>*) 0));
                }
                else if (pArg->vt == VT_DECIMAL)
                {
                    //Decimal maps to hyper in calls from COM -> UNO
                    // It does not matter if we create a sal_uInt64 or sal_Int64,
                    // because the UNO object is called through invocation which
                    //will do a type conversion if necessary
                    if (var.decVal.sign == 0)
                    {
                        // positive value
                        variantToAny( & var, rAny, getCppuType( (sal_uInt64*) 0),
                                      bReduceValueRange);
                    }
                    else 
                    {
                        //negative value
                        variantToAny( & var, rAny, getCppuType( (sal_Int64*) 0),
                                      bReduceValueRange);                        
                    }
                }
                else
                {
                    variantToAny( & var, rAny);
                }
                break;
            case TypeClass_BOOLEAN:			// VARIANT could be VARIANT_BOOL or other
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            case TypeClass_STRING:		// UString
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            case TypeClass_FLOAT: 		// float
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            case TypeClass_DOUBLE: 		// double
			if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
				variantToAny(& var, rAny);
			else if (hr == DISP_E_TYPEMISMATCH)
                bCannotConvert = true;
            else
				bFail = true;
			break;
            case TypeClass_BYTE:			// BYTE
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            case TypeClass_SHORT: 		// INT16
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_LONG:
                if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
                    variantToAny( & var, rAny, bReduceValueRange);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_HYPER:
                if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
                {
                    if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
                        || var.decVal.Hi32 > 0
                        || var.decVal.scale > 0)
                    {
                        bFail = true;
                        break;
                    }
                    sal_Int64 value = var.decVal.Lo64;
                    if (var.decVal.sign == DECIMAL_NEG)
                        value |=  SAL_CONST_UINT64(0x8000000000000000);
                    rAny <<= value;
                }
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_UNSIGNED_SHORT:	// UINT16
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_UNSIGNED_LONG:
                if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
                    variantToAny( & var, rAny, bReduceValueRange);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_UNSIGNED_HYPER:    
                if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
                {
                    if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
                    {
                        bFail = true;
                        break;
                    }
                    rAny <<= var.decVal.Lo64;
                }
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;                
                else
                    bFail = true;
                break;
            case TypeClass_TYPE:
                if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
                    variantToAny( & var, rAny);
                else if (hr == DISP_E_TYPEMISMATCH)
                    bCannotConvert = true;
                else
                    bFail = true;
                break;
            default:
// case TypeClass_SERVICE:	break;	// meta construct 
// case TypeClass_TYPEDEF: break;
// case TypeClass_UNION: 	break;	 			
// case TypeClass_MODULE:	break;		// module
// case TypeClass_EXCEPTION: break;	
// case TypeClass_ARRAY: break;    // there's no Array at the moment
// case TypeClass_UNKNOWN:	break;                
                bCannotConvert = true;
                break;
            }
        }
        if (bCannotConvert)
            throw CannotConvertException(
                OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
                      "Cannot convert the value of vartype :\"") +
                OUString::valueOf((sal_Int32) var.vt) +
                OUSTR("\"  to the expected UNO type of type class: ") +
                OUString::valueOf((sal_Int32) ptype.getTypeClass()),
                0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
            
        if (bFail)
            throw IllegalArgumentException(
                OUSTR("[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
                      "The provided VARIANT of type\" ") + OUString::valueOf((sal_Int32) var.vt) +
                OUSTR("\" is inappropriate for conversion!"), Reference<XInterface>(), -1);
    }
    catch (CannotConvertException &)
    {
        throw;
    }
    catch (IllegalArgumentException &)
    {
        throw;
    }
    catch (BridgeRuntimeError &)
    {
         throw;
    }
    catch (Exception & e)
    {
        throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
                                       "UnoConversionUtilities<T>::variantToAny ! Message : \n") +
                               e.Message);
    }
    catch(...)
    {
        throw BridgeRuntimeError(
            OUSTR("[automation bridge] unexpected exception in "
                  "UnoConversionUtilities<T>::variantToAny !"));
    }
}