PRBool XPCDispInterface::InspectIDispatch(JSContext * cx, ITypeInfo * pTypeInfo, PRUint32 members)
{
    HRESULT hResult;

    XPCDispInterface::Member * pInfo = mMembers;
    mMemberCount = 0;
    for(PRUint32 index = 0; index < members; index++ )
    {
        FUNCDESC* pFuncDesc;
        hResult = pTypeInfo->GetFuncDesc(index, &pFuncDesc );
        if(FAILED(hResult))
            continue;
        if(IsReflectable(pFuncDesc))
        {
            switch(pFuncDesc->invkind)
            {
                case INVOKE_PROPERTYPUT:
                case INVOKE_PROPERTYPUTREF:
                case INVOKE_PROPERTYGET:
                {
                    XPCDispInterface::Member * pExisting = FindExistingMember(mMembers, pInfo, pFuncDesc->memid);
                    if(pExisting == pInfo)
                    {
                        if(InitializeMember(cx, pTypeInfo, pFuncDesc, pInfo))
                        {
                            ++pInfo;
                            ++mMemberCount;
                        }
                    }
                    else
                    {
                        ConvertInvokeKind(pFuncDesc->invkind, *pExisting);
                    }
                    if(pFuncDesc->invkind == INVOKE_PROPERTYGET)
                    {
                        pExisting->SetGetterFuncDesc(pFuncDesc);
                    }
                }
                break;
                case INVOKE_FUNC:
                {
                    if(InitializeMember(cx, pTypeInfo, pFuncDesc, pInfo))
                    {
                        ++pInfo;
                        ++mMemberCount;
                    }
                }
                break;
                default:
                    pTypeInfo->ReleaseFuncDesc(pFuncDesc);
                break;
            }
        }
        else
        {
            pTypeInfo->ReleaseFuncDesc(pFuncDesc);
        }
    }
    return PR_TRUE;
}
/**
 * Sets a members type based on COM's INVOKEKIND
 */
static
void ConvertInvokeKind(INVOKEKIND invokeKind, XPCDispInterface::Member & member)
{
    switch (invokeKind)
    {
        case INVOKE_FUNC:
        {
            member.SetFunction();
        }
        break;
        case INVOKE_PROPERTYGET:
        {
            member.MakeGetter();
        }
        break;
        case INVOKE_PROPERTYPUT:
        {
            member.MakeSetter();
        }
        break;
        // TODO: Handle putref
        default:
        {
            NS_ERROR("Invalid invoke kind found in COM type info");
        }
        break;
    }
}
Exemple #3
0
// static
void
XPCThrower::Verbosify(XPCCallContext& ccx,
                      char** psz, PRBool own)
{
    char* sz = nsnull;

    if(ccx.HasInterfaceAndMember())
    {
        XPCNativeInterface* iface = ccx.GetInterface();
#ifdef XPC_IDISPATCH_SUPPORT
        NS_ASSERTION(ccx.GetIDispatchMember() == nsnull || 
                        ccx.GetMember() == nsnull,
                     "Both IDispatch member and regular XPCOM member "
                     "were set in XPCCallContext");
        char const * name;
        if(ccx.GetIDispatchMember())
        {
            XPCDispInterface::Member * member = 
                reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember());
            if(member && JSVAL_IS_STRING(member->GetName()))
            {
                name = JS_GetStringBytes(JSVAL_TO_STRING(member->GetName()));
            }
            else
                name = "Unknown";
        }
        else
            name = iface->GetMemberName(ccx, ccx.GetMember());
        sz = JS_smprintf("%s [%s.%s]",
                         *psz,
                         iface->GetNameString(),
                         name);
#else
        sz = JS_smprintf("%s [%s.%s]",
                         *psz,
                         iface->GetNameString(),
                         iface->GetMemberName(ccx, ccx.GetMember()));
#endif
    }

    if(sz)
    {
        if(own)
            JS_smprintf_free(*psz);
        *psz = sz;
    }
}
// static
void
XPCThrower::Verbosify(XPCCallContext& ccx,
                      char** psz, PRBool own)
{
    char* sz = nsnull;

    if(ccx.HasInterfaceAndMember())
    {
        XPCNativeInterface* iface = ccx.GetInterface();
        jsid id = JSID_VOID;
#ifdef XPC_IDISPATCH_SUPPORT
        NS_ASSERTION(ccx.GetIDispatchMember() == nsnull || 
                        ccx.GetMember() == nsnull,
                     "Both IDispatch member and regular XPCOM member "
                     "were set in XPCCallContext");
        if(ccx.GetIDispatchMember())
        {
            XPCDispInterface::Member * member = 
                reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember());
            if(member && JSID_IS_STRING(member->GetName()))
            {
                id = member->GetName();
            }
        }
        else
#endif
        {
            id = ccx.GetMember()->GetName();
        }
        JSAutoByteString bytes;
        const char *name = JSID_IS_VOID(id) ? "Unknown" : bytes.encode(ccx, JSID_TO_STRING(id));
        if(!name)
        {
            name = "";
        }
        sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name);
    }

    if(sz)
    {
        if(own)
            JS_smprintf_free(*psz);
        *psz = sz;
    }
}
static
XPCDispInterface::Member * FindExistingMember(XPCDispInterface::Member * first,
                                              XPCDispInterface::Member * last,
                                              MEMBERID memberID)
{
    // Iterate backward since the last one in is the most likely match
    XPCDispInterface::Member * cur = last;
    if (cur != first)
    {
        do 
        {
            --cur;
            if(cur->GetMemID() == memberID)
                return cur;
        } while(cur != first);
    } 
    // no existing property, return the new one
    return last;
}
JSBool XPCDispObject::Invoke(XPCCallContext & ccx, CallMode mode)
{
    nsresult rv = ccx.CanCallNow();
    if(NS_FAILED(rv))
    {
        // If the security manager is complaining then this is not really an
        // internal error in xpconnect. So, no reason to botch the assertion.
        NS_ASSERTION(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, 
                     "hmm? CanCallNow failed in XPCDispObject::Invoke. "
                     "We are finding out about this late!");
        XPCThrower::Throw(rv, ccx);
        return JS_FALSE;
    }

    // TODO: Remove type cast and change GetIDispatchMember to use the correct type
    XPCDispInterface::Member* member = reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember());
    XPCJSRuntime* rt = ccx.GetRuntime();
    XPCContext* xpcc = ccx.GetXPCContext();
    XPCPerThreadData* tls = ccx.GetThreadData();
    
    jsval* argv = ccx.GetArgv();
    uintN argc = ccx.GetArgc();

    tls->SetException(nsnull);
    xpcc->SetLastResult(NS_ERROR_UNEXPECTED);

    // set up the method index and do the security check if needed

    PRUint32 secFlag;
    PRUint32 secAction;

    switch(mode)
    {
        case CALL_METHOD:
            secFlag   = nsIXPCSecurityManager::HOOK_CALL_METHOD;
            secAction = nsIXPCSecurityManager::ACCESS_CALL_METHOD;
            break;
        case CALL_GETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_GET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
            break;
        case CALL_SETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_SET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
            break;
        default:
            NS_ASSERTION(0,"bad value");
            return JS_FALSE;
    }
    jsval name = member->GetName();

    nsIXPCSecurityManager* sm = xpcc->GetAppropriateSecurityManager(secFlag);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    if(sm && NS_FAILED(sm->CanAccess(secAction, &ccx, ccx,
                                     ccx.GetFlattenedJSObject(),
                                     wrapper->GetIdentityObject(),
                                     wrapper->GetClassInfo(), name,
                                     wrapper->GetSecurityInfoAddr())))
    {
        // the security manager vetoed. It should have set an exception.
        return JS_FALSE;
    }

    IDispatch * pObj = reinterpret_cast<IDispatch*>
                                       (ccx.GetTearOff()->GetNative());
    PRUint32 args = member->GetParamCount();
    uintN err;
    // Make sure setter has one argument
    if(mode == CALL_SETTER)
        args = 1;
    // Allow for optional parameters. We'll let COM handle the error if there
    // are not enough parameters
    if(argc < args)
        args = argc;
    XPCDispParams * params = new XPCDispParams(args);
    jsval val;
    // If this is a setter, we just need to convert the first parameter
    if(mode == CALL_SETTER)
    {
        params->SetNamedPropID();
        if(!XPCDispConvert::JSToCOM(ccx, argv[0], params->GetParamRef(0), err))
        {
            delete params;
            return ThrowBadParam(err, 0, ccx);
        }
    }
    else if(mode != CALL_GETTER)    // This is a function
    {
        // Convert the arguments to the function
        for(PRUint32 index = 0; index < args; ++index)
        {
            const XPCDispInterface::Member::ParamInfo & paramInfo = member->GetParamInfo(index);
            if(paramInfo.IsIn())
            {
                val = argv[index];
                if(paramInfo.IsOut())
                {
                    if(JSVAL_IS_PRIMITIVE(val) ||
                        !OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(val),
                                          rt->GetStringID(XPCJSRuntime::IDX_VALUE),
                                          &val))
                    {
                        delete params;
                        return ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, index, ccx);
                    }
                    paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
                }
                if(!XPCDispConvert::JSToCOM(ccx, val, params->GetParamRef(index), err, paramInfo.IsOut()))
                {
                    delete params;
                    return ThrowBadParam(err, index, ccx);
                }
            }
            else
            {
                paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
            }
        }
    }
    // If this is a parameterized property
    if(member->IsParameterizedProperty())
    {
        // We need to get a parameterized property object to return to JS
        // NewInstance takes ownership of params
        if(XPCDispParamPropJSClass::NewInstance(ccx, wrapper,
                                                member->GetDispID(),
                                                params, &val))
        {
            ccx.SetRetVal(val);
            if(!JS_IdToValue(ccx, 1, &val))
            {
                // This shouldn't fail
                NS_ERROR("JS_IdToValue failed in XPCDispParamPropJSClass::NewInstance");
                return JS_FALSE;
            }
            JS_SetCallReturnValue2(ccx, val);
            return JS_TRUE;
        }
        // NewInstance would only fail if there was an out of memory problem
        JS_ReportOutOfMemory(ccx);
        delete params;
        return JS_FALSE;
    }
    JSBool retval = Dispatch(ccx, pObj, member->GetDispID(), mode, params, &val, member, rt);
    if(retval && mode == CALL_SETTER)
    {
        ccx.SetRetVal(argv[0]);
    }
    else
    {
        ccx.SetRetVal(val);
    }
    delete params;
    return retval;
}