Example #1
0
nsresult
xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex,
                                    const nsXPTParamInfo* param,
                                    uint16 dimension,
                                    nsXPTType* type)
{
    if(!EnsureResolved())
        return NS_ERROR_UNEXPECTED;

    if(methodIndex < mMethodBaseIndex)
        return mParent->
            GetTypeForParam(methodIndex, param, dimension, type);

    if(methodIndex >= mMethodBaseIndex + 
                      mDescriptor->num_methods)
    {
        NS_ERROR("bad index");
        return NS_ERROR_INVALID_ARG;
    }

    const XPTTypeDescriptor *td;

    if(dimension) {
        nsresult rv = GetTypeInArray(param, dimension, &td);
        if(NS_FAILED(rv))
            return rv;
    }
    else
        td = &param->type;

    *type = nsXPTType(td->prefix);
    return NS_OK;
}
Example #2
0
// static 
JSBool 
XPCVariant::VariantDataToJS(XPCCallContext& ccx, 
                            nsIVariant* variant,
                            JSObject* scope, nsresult* pErr,
                            jsval* pJSVal)
{
    // Get the type early because we might need to spoof it below.
    PRUint16 type;
    if(NS_FAILED(variant->GetDataType(&type)))
        return JS_FALSE;

    nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
    if(xpcvariant)
    {
        jsval realVal = xpcvariant->GetJSVal();
        if(JSVAL_IS_PRIMITIVE(realVal) || 
           type == nsIDataType::VTYPE_ARRAY ||
           type == nsIDataType::VTYPE_ID)
        {
            // Not a JSObject (or is a JSArray or is a JSObject representing 
            // an nsID),.
            // So, just pass through the underlying data.
            *pJSVal = realVal;
            return JS_TRUE;
        }

        // else, it's an object and we really need to double wrap it if we've 
        // already decided that its 'natural' type is as some sort of interface.
        
        // We just fall through to the code below and let it do what it does.
    }

    // The nsIVariant is not a XPCVariant (or we act like it isn't).
    // So we extract the data and do the Right Thing.
    
    // We ASSUME that the variant implementation can do these conversions...

    nsXPTCVariant xpctvar;
    nsID iid;
    nsAutoString astring;
    nsCAutoString cString;
    nsUTF8String utf8String;
    PRUint32 size;
    xpctvar.flags = 0;
    JSBool success;

    switch(type)
    {
        case nsIDataType::VTYPE_INT8:        
        case nsIDataType::VTYPE_INT16:        
        case nsIDataType::VTYPE_INT32:        
        case nsIDataType::VTYPE_INT64:        
        case nsIDataType::VTYPE_UINT8:        
        case nsIDataType::VTYPE_UINT16:        
        case nsIDataType::VTYPE_UINT32:        
        case nsIDataType::VTYPE_UINT64:        
        case nsIDataType::VTYPE_FLOAT:        
        case nsIDataType::VTYPE_DOUBLE:        
        {
            // Easy. Handle inline.
            if(NS_FAILED(variant->GetAsDouble(&xpctvar.val.d)))
                return JS_FALSE;
            return JS_NewNumberValue(ccx, xpctvar.val.d, pJSVal);
        }
        case nsIDataType::VTYPE_BOOL:        
        {
            // Easy. Handle inline.
            if(NS_FAILED(variant->GetAsBool(&xpctvar.val.b)))
                return JS_FALSE;
            *pJSVal = BOOLEAN_TO_JSVAL(xpctvar.val.b);
            return JS_TRUE;
        }
        case nsIDataType::VTYPE_CHAR: 
            if(NS_FAILED(variant->GetAsChar(&xpctvar.val.c)))
                return JS_FALSE;
            xpctvar.type = (uint8)TD_CHAR;
            break;
        case nsIDataType::VTYPE_WCHAR:        
            if(NS_FAILED(variant->GetAsWChar(&xpctvar.val.wc)))
                return JS_FALSE;
            xpctvar.type = (uint8)TD_WCHAR;
            break;
        case nsIDataType::VTYPE_ID:        
            if(NS_FAILED(variant->GetAsID(&iid)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_PNSIID | XPT_TDP_POINTER);
            xpctvar.val.p = &iid;
            break;
        case nsIDataType::VTYPE_ASTRING:        
            if(NS_FAILED(variant->GetAsAString(astring)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_ASTRING | XPT_TDP_POINTER);
            xpctvar.val.p = &astring;
            break;
        case nsIDataType::VTYPE_DOMSTRING:
            if(NS_FAILED(variant->GetAsAString(astring)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_DOMSTRING | XPT_TDP_POINTER);
            xpctvar.val.p = &astring;
            break;
        case nsIDataType::VTYPE_CSTRING:            
            if(NS_FAILED(variant->GetAsACString(cString)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_CSTRING | XPT_TDP_POINTER);
            xpctvar.val.p = &cString;
            break;
        case nsIDataType::VTYPE_UTF8STRING:            
            if(NS_FAILED(variant->GetAsAUTF8String(utf8String)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_UTF8STRING | XPT_TDP_POINTER);
            xpctvar.val.p = &utf8String;
            break;       
        case nsIDataType::VTYPE_CHAR_STR:       
            if(NS_FAILED(variant->GetAsString((char**)&xpctvar.val.p)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_PSTRING | XPT_TDP_POINTER);
            xpctvar.SetValIsAllocated();
            break;
        case nsIDataType::VTYPE_STRING_SIZE_IS:
            if(NS_FAILED(variant->GetAsStringWithSize(&size, 
                                                      (char**)&xpctvar.val.p)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_PSTRING_SIZE_IS | XPT_TDP_POINTER);
            break;
        case nsIDataType::VTYPE_WCHAR_STR:        
            if(NS_FAILED(variant->GetAsWString((PRUnichar**)&xpctvar.val.p)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_PWSTRING | XPT_TDP_POINTER);
            xpctvar.SetValIsAllocated();
            break;
        case nsIDataType::VTYPE_WSTRING_SIZE_IS:        
            if(NS_FAILED(variant->GetAsWStringWithSize(&size, 
                                                      (PRUnichar**)&xpctvar.val.p)))
                return JS_FALSE;
            xpctvar.type = (uint8)(TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER);
            break;
        case nsIDataType::VTYPE_INTERFACE:        
        case nsIDataType::VTYPE_INTERFACE_IS:        
        {
            nsID* piid;
            if(NS_FAILED(variant->GetAsInterface(&piid, &xpctvar.val.p)))
                return JS_FALSE;

            iid = *piid;
            nsMemory::Free((char*)piid);

            xpctvar.type = (uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER);
            if(xpctvar.val.p)
                xpctvar.SetValIsInterface();
            break;
        }
        case nsIDataType::VTYPE_ARRAY:
        {
            nsDiscriminatedUnion du;
            nsVariant::Initialize(&du);
            nsresult rv;

            rv = variant->GetAsArray(&du.u.array.mArrayType,
                                     &du.u.array.mArrayInterfaceID,
                                     &du.u.array.mArrayCount,
                                     &du.u.array.mArrayValue);
            if(NS_FAILED(rv))
                return JS_FALSE;
        
            // must exit via VARIANT_DONE from here on...
            du.mType = nsIDataType::VTYPE_ARRAY;
            success = JS_FALSE;

            nsXPTType conversionType;
            PRUint16 elementType = du.u.array.mArrayType;
            const nsID* pid = nsnull;

            switch(elementType)
            {
                case nsIDataType::VTYPE_INT8:        
                case nsIDataType::VTYPE_INT16:        
                case nsIDataType::VTYPE_INT32:        
                case nsIDataType::VTYPE_INT64:        
                case nsIDataType::VTYPE_UINT8:        
                case nsIDataType::VTYPE_UINT16:        
                case nsIDataType::VTYPE_UINT32:        
                case nsIDataType::VTYPE_UINT64:        
                case nsIDataType::VTYPE_FLOAT:        
                case nsIDataType::VTYPE_DOUBLE:        
                case nsIDataType::VTYPE_BOOL:        
                case nsIDataType::VTYPE_CHAR:        
                case nsIDataType::VTYPE_WCHAR:        
                    conversionType = nsXPTType((uint8)elementType);
                    break;

                case nsIDataType::VTYPE_ID:        
                case nsIDataType::VTYPE_CHAR_STR:        
                case nsIDataType::VTYPE_WCHAR_STR:        
                    conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
                    break;

                case nsIDataType::VTYPE_INTERFACE:        
                    pid = &NS_GET_IID(nsISupports);
                    conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
                    break;

                case nsIDataType::VTYPE_INTERFACE_IS:        
                    pid = &du.u.array.mArrayInterfaceID;
                    conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
                    break;

                // The rest are illegal.
                case nsIDataType::VTYPE_VOID:        
                case nsIDataType::VTYPE_ASTRING:        
                case nsIDataType::VTYPE_DOMSTRING:        
                case nsIDataType::VTYPE_CSTRING:        
                case nsIDataType::VTYPE_UTF8STRING:        
                case nsIDataType::VTYPE_WSTRING_SIZE_IS:        
                case nsIDataType::VTYPE_STRING_SIZE_IS:        
                case nsIDataType::VTYPE_ARRAY:
                case nsIDataType::VTYPE_EMPTY_ARRAY:
                case nsIDataType::VTYPE_EMPTY:
                default:
                    NS_ERROR("bad type in array!");
                    goto VARIANT_DONE;
            }

            success = 
                XPCConvert::NativeArray2JS(ccx, pJSVal, 
                                           (const void**)&du.u.array.mArrayValue,
                                           conversionType, pid,
                                           du.u.array.mArrayCount, 
                                           scope, pErr);

VARIANT_DONE:                                
            nsVariant::Cleanup(&du);
            return success;
        }        
        case nsIDataType::VTYPE_EMPTY_ARRAY: 
        {
            JSObject* array = JS_NewArrayObject(ccx, 0, nsnull);
            if(!array) 
                return JS_FALSE;
            *pJSVal = OBJECT_TO_JSVAL(array);
            return JS_TRUE;
        }
        case nsIDataType::VTYPE_VOID:        
        case nsIDataType::VTYPE_EMPTY:
            *pJSVal = JSVAL_VOID;
            return JS_TRUE;
        default:
            NS_ERROR("bad type in variant!");
            return JS_FALSE;
    }

    // If we are here then we need to convert the data in the xpctvar.
    
    if(xpctvar.type.TagPart() == TD_PSTRING_SIZE_IS ||
       xpctvar.type.TagPart() == TD_PWSTRING_SIZE_IS)
    {
        success = XPCConvert::NativeStringWithSize2JS(ccx, pJSVal,
                                                      (const void*)&xpctvar.val,
                                                      xpctvar.type,
                                                      size, pErr);
    }
    else
    {
        success = XPCConvert::NativeData2JS(ccx, pJSVal,
                                            (const void*)&xpctvar.val,
                                            xpctvar.type,
                                            &iid, scope, pErr);
    }

    if(xpctvar.IsValAllocated())
        nsMemory::Free((char*)xpctvar.val.p);
    else if(xpctvar.IsValInterface())
        ((nsISupports*)xpctvar.val.p)->Release();

    return success;
}
Example #3
0
// static
JSBool
XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array,
                                     jsuint length, 
                                     nsXPTType* resultType, nsID* resultID)    
{
    Type state = tUnk;
    Type type;
       
    for(jsuint i = 0; i < length; i++)
    {
        jsval val;
        if(!JS_GetElement(ccx, array, i, &val))
            return JS_FALSE;
           
        if(JSVAL_IS_INT(val))
            type = tInt;
        else if(JSVAL_IS_DOUBLE(val))
            type = tDbl;
        else if(JSVAL_IS_BOOLEAN(val))
            type = tBool;
        else if(JSVAL_IS_VOID(val))
        {
            state = tVar;
            break;
        }
        else if(JSVAL_IS_NULL(val))
            type = tNull;
        else if(JSVAL_IS_STRING(val))
            type = tStr;
        else
        {
            NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!");
            JSObject* jsobj = JSVAL_TO_OBJECT(val);
            if(JS_IsArrayObject(ccx, jsobj))
                type = tArr;
            else if(xpc_JSObjectIsID(ccx, jsobj))
                type = tID;
            else
                type = tISup;
        }

        NS_ASSERTION(state != tErr, "bad state table!");
        NS_ASSERTION(type  != tErr, "bad type!");
        NS_ASSERTION(type  != tVar, "bad type!");
        NS_ASSERTION(type  != tUnk, "bad type!");

        state = StateTable[state][type];
        
        NS_ASSERTION(state != tErr, "bad state table!");
        NS_ASSERTION(state != tUnk, "bad state table!");
        
        if(state == tVar)
            break;
    }

    switch(state)
    {
        case tInt : 
            *resultType = nsXPTType((uint8)TD_INT32);
            break;
        case tDbl : 
            *resultType = nsXPTType((uint8)TD_DOUBLE);
            break;
        case tBool:
            *resultType = nsXPTType((uint8)TD_BOOL);
            break;
        case tStr : 
            *resultType = nsXPTType((uint8)(TD_PWSTRING | XPT_TDP_POINTER));
            break;
        case tID  : 
            *resultType = nsXPTType((uint8)(TD_PNSIID | XPT_TDP_POINTER));
            break;
        case tISup: 
            *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER));
            *resultID = NS_GET_IID(nsISupports);
            break;
        case tNull: 
            // FALL THROUGH
        case tVar :
            *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER));
            *resultID = NS_GET_IID(nsIVariant);
            break;
        case tArr : 
            // FALL THROUGH
        case tUnk : 
            // FALL THROUGH
        case tErr : 
            // FALL THROUGH
        default:
            NS_ERROR("bad state");
            return JS_FALSE;
    }
    return JS_TRUE;
}
/**
 * Asynchronous processing :
 * 1-> WSPProxy::CallMethod
 * 2  -> WSPCallContext::CallAsync
 * 3    -> nsSOAPCall::AsyncInvoke
 * 4      -> nsXXXSOAPTransport::AsyncCall
 * 5        -> nsIXMLHttpRequest::Send, nsXXXSOAPTransportCompletion::AddEventListener
 * ---- asynchronous ----
 * 6          -> nsXXXSOAPTransportCompletion::HandleEvent
 * 7            -> WSPCallContext::HandleResponse, 
 *                 WSPCallContext::CallCompletionListener
 * 8              -> nsSOAPBlock::SetSchemaType, nsSOAPBlock::GetValue
 * 9                -> nsSOAPEncoding::Decode, nsDefaultSOAPDecode::Decode
 * 10                 -> WSPProxy::CallCompleted
 */
NS_IMETHODIMP
WSPProxy::CallMethod(PRUint16 methodIndex,
                     const XPTMethodDescriptor* info,
                     nsXPTCMiniVariant* params)
{
  nsresult rv;
  nsCOMPtr<nsIWebServiceCallContext> cc;
  nsCOMPtr<nsIWSDLBinding> binding;

  if (methodIndex < 3) {
    NS_ERROR("WSPProxy: bad method index");
    return NS_ERROR_FAILURE;
  }

  // The first method in the interface for async callers is the
  // one to set the async listener
  if (mIsAsync && (methodIndex == 3)) {
    nsISupports* listener = static_cast<nsISupports*>(params[0].val.p);
    mAsyncListener = listener;
    return NS_OK;
  }

  PRUint32 methodOffset;
  if (mIsAsync) {
    methodOffset = 4;
  }
  else {
    methodOffset = 3;
  }

  nsCOMPtr<nsIWSDLOperation> operation;
  rv = mPort->GetOperation(methodIndex - methodOffset,
                           getter_AddRefs(operation));
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsIWSDLMessage> input;
  rv = operation->GetInput(getter_AddRefs(input));
  if (NS_FAILED(rv)) {
    return rv;
  }

  // Create the call instance
  nsCOMPtr<nsISOAPCall> call = do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv);
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsISOAPEncoding> encoding =
    do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv);
  if (NS_FAILED(rv)) {
    return rv;
  }
  call->SetEncoding(encoding);

  // Get the method name and target object uri
  nsAutoString methodName, targetObjectURI;
  rv = operation->GetBinding(getter_AddRefs(binding));
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsISOAPOperationBinding> operationBinding =
    do_QueryInterface(binding, &rv);
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsAutoString soapAction;
  operationBinding->GetSoapAction(soapAction);
  call->SetActionURI(soapAction);

  PRUint16 style;
  operationBinding->GetStyle(&style);
  // If the style is RPC, find the method name and target object URI.
  // If it is document-style, these are both left blank.
  if (style == nsISOAPPortBinding::STYLE_RPC) {
    operation->GetName(methodName);
    rv = input->GetBinding(getter_AddRefs(binding));
    if (NS_FAILED(rv)) {
      return rv;
    }
    nsCOMPtr<nsISOAPMessageBinding> messageBinding =
      do_QueryInterface(binding, &rv);
    if (NS_FAILED(rv)) {
      return rv;
    }
    messageBinding->GetNamespace(targetObjectURI);
  }

  // Set the transport URI
  rv = mPort->GetBinding(getter_AddRefs(binding));
  if (NS_FAILED(rv)) {
    return rv;
  }
  nsCOMPtr<nsISOAPPortBinding> portBinding = do_QueryInterface(binding, &rv);
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsAutoString address;
  portBinding->GetAddress(address);
  rv = call->SetTransportURI(address);
  if (NS_FAILED(rv)) {
    return rv;
  }

  PRUint16 version;
  portBinding->GetSoapVersion(&version);
  if (version == nsISOAPMessage::VERSION_UNKNOWN) {
    version = nsISOAPMessage::VERSION_1_1;
  }

  // Set up the parameters to the call
  PRUint32 i, partCount;
  input->GetPartCount(&partCount);

  PRUint32 maxParamIndex = info->num_args - 1;

  // Iterate through the parts to figure out how many are
  // body vs. header blocks
  nsCOMPtr<nsIWSDLPart> part;
  PRUint32 headerCount = 0, bodyCount = 0;

  for (i = 0; i < partCount; i++) {
    rv = input->GetPart(i, getter_AddRefs(part));
    if (NS_FAILED(rv)) {
      return rv;
    }

    rv = part->GetBinding(getter_AddRefs(binding));
    if (NS_FAILED(rv)) {
      return rv;
    }

    nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding, &rv);
    if (NS_FAILED(rv)) {
      return rv;
    }

    PRUint16 location;
    partBinding->GetLocation(&location);
    if (location == nsISOAPPartBinding::LOCATION_HEADER) {
      headerCount++;
    }
    else if (location == nsISOAPPartBinding::LOCATION_BODY) {
      bodyCount++;
    }
  }

  // Allocate parameter and header blocks
  nsISOAPParameter** bodyBlocks = nsnull;
  if (bodyCount) {
    bodyBlocks = static_cast<nsISOAPParameter**>
                            (nsMemory::Alloc(bodyCount * sizeof(nsISOAPParameter*)));
    if (!bodyBlocks) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
    for (i = 0; i < bodyCount; i++) {
      rv = CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[i]);
      if (NS_FAILED(rv)) {
        NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, bodyBlocks);

        return rv;
      }
    }
  }

  nsISOAPHeaderBlock** headerBlocks = nsnull;
  if (headerCount) {
    headerBlocks = static_cast<nsISOAPHeaderBlock**>
                              (nsMemory::Alloc(headerCount * sizeof(nsISOAPHeaderBlock*)));
    if (!headerBlocks) {
      if (bodyBlocks) {
        NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
      }
      return NS_ERROR_OUT_OF_MEMORY;
    }
    for (i = 0; i < headerCount; i++) {
      rv = CallCreateInstance(NS_SOAPHEADERBLOCK_CONTRACTID, &headerBlocks[i]);
      if (NS_FAILED(rv)) {
        if (bodyBlocks) {
          NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
        }
        NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, headerBlocks);

        return rv;
      }
    }
  }

  // Now iterate through the parameters and set up the parameter blocks
  PRUint32 bodyEntry = 0, headerEntry = 0, paramIndex = 0;
  for (i = 0; i < partCount; paramIndex++, i++) {
    input->GetPart(i, getter_AddRefs(part));
    part->GetBinding(getter_AddRefs(binding));
    nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding);
    PRUint16 location;
    partBinding->GetLocation(&location);

    nsCOMPtr<nsISOAPBlock> block;
    if (location == nsISOAPPartBinding::LOCATION_HEADER) {
      block = do_QueryInterface(headerBlocks[headerEntry++]);
    }
    else if (location == nsISOAPPartBinding::LOCATION_BODY) {
      block = do_QueryInterface(bodyBlocks[bodyEntry++]);
    }

    if (!block) {
      rv = NS_ERROR_FAILURE;
      goto call_method_end;
    }

    // Get the name, namespaceURI and type of the block based on
    // information from the WSDL part. If the schema component
    // associated with the part is an element, these values come
    // from the schema description of the element. If it is a
    // type, then the values are gathered from elsewhere.
    nsCOMPtr<nsISchemaComponent> schemaComponent;
    rv = part->GetSchemaComponent(getter_AddRefs(schemaComponent));
    if (NS_FAILED(rv)) {
      goto call_method_end;
    }

    nsCOMPtr<nsISchemaType> type;
    nsAutoString blockName, blockNamespace;
    nsCOMPtr<nsISchemaElement> element = do_QueryInterface(schemaComponent);

    if (element) {
      rv = element->GetType(getter_AddRefs(type));
      if (NS_FAILED(rv)) {
        goto call_method_end;
      }

      element->GetName(blockName);
      element->GetTargetNamespace(blockNamespace);
    }
    else {
      type = do_QueryInterface(schemaComponent);

      nsAutoString paramName;
      part->GetName(paramName);

      blockName.Assign(paramName);
      partBinding->GetNamespace(blockNamespace);
    }

    block->SetName(blockName);
    block->SetNamespaceURI(blockNamespace);
    block->SetSchemaType(type);

    nsAutoString encodingStyle;
    PRUint16 use;

    partBinding->GetUse(&use);
    // XXX Need a way to specify that a block should not be
    // encoded.
    if (use == nsISOAPPartBinding::USE_ENCODED) {
      partBinding->GetEncodingStyle(encodingStyle);
      if (!encodingStyle.IsEmpty()) {
        nsCOMPtr<nsISOAPEncoding> partEncoding;
        encoding->GetAssociatedEncoding(encodingStyle, PR_FALSE,
                                        getter_AddRefs(partEncoding));
        block->SetEncoding(partEncoding);
      }
    }

    // Look ahead in the param info array to see if the current part has to be
    // treated as an array. If so then get the array length from the current
    // param and increment the param index.

    PRUint32 arrayLength;

    if (paramIndex < maxParamIndex &&
        nsXPTType(info->params[paramIndex + 1].type.prefix).IsArray()) {
      arrayLength = params[paramIndex++].val.u32;
    }
    else {
      arrayLength = 0;
    }

    NS_ASSERTION(paramIndex <= maxParamIndex,
                 "WSDL/IInfo param count mismatch");

    const nsXPTParamInfo& paramInfo = info->params[paramIndex];

    nsCOMPtr<nsIVariant> value;
    rv = ParameterToVariant(mPrimaryInterface, methodIndex,
                            &paramInfo, params[paramIndex],
                            arrayLength, getter_AddRefs(value));
    if (NS_FAILED(rv)) {
      goto call_method_end;
    }

    block->SetValue(value);
  }

  // Encode the parameters to the call
  rv = call->Encode(version,
                    methodName, targetObjectURI,
                    headerCount, headerBlocks,
                    bodyCount, bodyBlocks);
  if (NS_FAILED(rv)) {
    goto call_method_end;
  }

  WSPCallContext* ccInst;
  ccInst = new WSPCallContext(this, call, methodName, operation);
  if (!ccInst) {
    rv = NS_ERROR_OUT_OF_MEMORY;
    goto call_method_end;
  }
  cc = ccInst;

  if (mIsAsync) {
    PRUint8 pcount;
    pcount = info->num_args;
    // There has to be at least one parameter - the retval.
    if (pcount == 0) {
      rv = NS_ERROR_FAILURE;
      goto call_method_end;
    }

#ifdef DEBUG
    // The last one should be the retval.
    const nsXPTParamInfo& retParamInfo = info->params[pcount - 1];
    if (!retParamInfo.IsRetval()) {
      rv = NS_ERROR_FAILURE;
      goto call_method_end;
    }

    // It should be an interface pointer
    const nsXPTType& retType = retParamInfo.GetType();
    if (!retType.IsInterfacePointer()) {
      rv = NS_ERROR_FAILURE;
      goto call_method_end;
    }
#endif

    nsIWebServiceCallContext** retval =
      static_cast<nsIWebServiceCallContext**>(params[pcount-1].val.p);
    if (!retval) {
      rv = NS_ERROR_FAILURE;
      goto call_method_end;
    }
    *retval = cc;
    NS_ADDREF(*retval);

    rv = ccInst->CallAsync(methodIndex, mAsyncListener);
    if (NS_FAILED(rv)) {
      goto call_method_end;
    }

    mPendingCalls.AppendObject(ccInst);
  }
  else {
    rv = ccInst->CallSync(methodIndex, params);
  }

call_method_end:
  if (bodyBlocks) {
    NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
  }
  if (headerBlocks) {
    NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(headerCount, headerBlocks);
  }
  return rv;
}