Back to index

lightning-sunbird  0.9+nobinonly
wspinfoservice.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   John Bandhauer (jband@netscape.com) (Original author)
00024  *   Vidur Apparao (vidur@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsIVariant.h"
00041 #include "wspprivate.h"
00042 
00043 /***************************************************************************/
00044 // IIDX is used as a way to hold and share our common set of interface
00045 // indexes.
00046 
00047 class IIDX {
00048 public:
00049   enum IndexID {
00050     IDX_nsISupports,
00051     IDX_nsIException,
00052     IDX_nsIWebServiceCallContext,
00053     IDX_nsIVariant,
00054     IDX_nsIDOMElement,
00055 
00056     IDX_Count  // Just a count of the above.
00057   };
00058 
00059   PRUint16  Get(IndexID id) const
00060   {
00061     NS_ASSERTION(id < IDX_Count, "bad");
00062     return mData[id];
00063   }
00064 
00065   PRUint16* GetAddr(IndexID id)
00066   {
00067     NS_ASSERTION(id < IDX_Count, "bad");
00068     return &mData[id];
00069   }
00070 
00071 private:
00072   PRUint16 mData[IDX_Count];
00073 };
00074 
00075 /***************************************************************************/
00076 // ParamAccumulator helps us build param arrays without knowing the length
00077 // ahead of time. We later memcpy out of the array into space allocated using
00078 // nsIGenericInterfaceInfoSet::AllocateParamArray.
00079 
00080 class ParamAccumulator
00081 {
00082 private:
00083   enum {
00084     MAX_BUILTIN = 8,
00085     ALLOCATION_INCREMENT = 16,
00086     MAX_TOTAL = 255
00087   }; // The typelib format limits us to 255 params.
00088 
00089 public:
00090   PRUint16 GetCount() const
00091   {
00092     return mCount;
00093   }
00094   XPTParamDescriptor* GetArray()
00095   {
00096     return mArray;
00097   }
00098   void Clear()
00099   {
00100     mCount = 0;
00101   }
00102 
00103   XPTParamDescriptor* GetNextParam();
00104 
00105   ParamAccumulator()
00106     : mCount(0), mAvailable(MAX_BUILTIN), mArray(mBuiltinSpace)
00107   {
00108   }
00109 
00110   ~ParamAccumulator()
00111   {
00112     if(mArray != mBuiltinSpace)
00113       delete [] mArray;
00114   }
00115 private:
00116   PRUint16            mCount;
00117   PRUint16            mAvailable;
00118   XPTParamDescriptor* mArray;
00119   XPTParamDescriptor  mBuiltinSpace[MAX_BUILTIN];
00120 };
00121 
00122 XPTParamDescriptor*
00123 ParamAccumulator::GetNextParam()
00124 {
00125   if (mCount == MAX_TOTAL) {
00126     NS_WARNING("Too many params!");
00127     return nsnull;
00128   }
00129   if (mCount == mAvailable) {
00130     PRUint16 newAvailable = mAvailable + ALLOCATION_INCREMENT;
00131     XPTParamDescriptor* newArray = new XPTParamDescriptor[newAvailable];
00132     if (!newArray) {
00133       return nsnull;
00134     }
00135 
00136     memcpy(newArray, mArray, newAvailable * sizeof(XPTParamDescriptor));
00137 
00138     if (mArray != mBuiltinSpace) {
00139       // The old array was heap allocated, delete so that we don't
00140       // leak it.
00141       delete [] mArray;
00142     }
00143 
00144     mArray = newArray;
00145     mAvailable = newAvailable;
00146   }
00147 
00148   XPTParamDescriptor* p = &mArray[mCount++];
00149   memset(p, 0, sizeof(XPTParamDescriptor));
00150   return p; 
00151 }
00152 
00153 /***************************************************************************/
00154 // NewUniqueID generates a uuid that is intended to be locally unique for the
00155 // life of the process. These uuids should not be shared with other processes
00156 // or persisted. 
00157 
00158 static nsresult
00159 NewUniqueID(nsID *aID)
00160 {
00161   // XXX Hack Alert. This was generated on jband's 'bugsfree' machine and
00162   // *ought* not to conflict with any existing guids. We should find a
00163   // more foolproof crossplatfor dynmic guidgen scheme.
00164 
00165   // {00000000-1063-11d6-98A8-00C04FA0D259}
00166   static const nsID sBaseGuid =
00167     {0x00000000, 0x1063, 0x11d6,
00168       {0x98, 0xa8, 0x0, 0xc0, 0x4f, 0xa0, 0xd2, 0x59}};
00169 
00170   static PRInt32 sSerialNumber = 0;
00171 
00172   *aID = sBaseGuid;
00173   aID->m0 = (PRUint32) PR_AtomicIncrement(&sSerialNumber);
00174   return NS_OK;
00175 }
00176 
00177 /***************************************************************************/
00178 // FindInterfaceByName finds an interface info keyed by interface name. It
00179 // searches the super manager and any additional managers
00180 
00181 static nsresult
00182 FindInterfaceByName(const char* aName, nsIInterfaceInfoSuperManager* iism,
00183                     nsIInterfaceInfoManager **aSet, nsIInterfaceInfo **_retval)
00184 {
00185   NS_ENSURE_ARG_POINTER(aSet);
00186   if (NS_SUCCEEDED(iism->GetInfoForName(aName, _retval)) && *_retval) {
00187     NS_ADDREF(*aSet = iism);
00188     return NS_OK;
00189   }
00190 
00191   PRBool yes;
00192   nsCOMPtr<nsISimpleEnumerator> list;
00193 
00194   if (NS_SUCCEEDED(iism->HasAdditionalManagers(&yes)) && yes &&
00195       NS_SUCCEEDED(iism->EnumerateAdditionalManagers(getter_AddRefs(list))) &&
00196       list) {
00197     PRBool more;
00198     nsCOMPtr<nsIInterfaceInfoManager> current;
00199 
00200     while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more &&
00201            NS_SUCCEEDED(list->GetNext(getter_AddRefs(current))) && current) {
00202       if (NS_SUCCEEDED(current->GetInfoForName(aName, _retval)) &&
00203           *_retval) {
00204         NS_ADDREF(*aSet = current.get());
00205         return NS_OK;
00206       }
00207     }
00208   }
00209 
00210   return NS_ERROR_NO_INTERFACE;
00211 }
00212 
00213 /***************************************************************************/
00214 // FindInterfaceByName finds the *index* of an interface info in the given
00215 // generic info set keyed by interface name. 
00216 
00217 static nsresult
00218 FindInterfaceIndexByName(const char* aName, nsIInterfaceInfoSuperManager* iism,
00219                          nsIGenericInterfaceInfoSet* aSet, PRUint16* aIndex)
00220 {
00221   nsresult rv = aSet->IndexOfByName(aName, aIndex);
00222   if (NS_SUCCEEDED(rv)) {
00223     return NS_OK;
00224   }
00225 
00226   nsCOMPtr<nsIInterfaceInfo> info;
00227   nsCOMPtr<nsIInterfaceInfoManager> unused;
00228   rv = FindInterfaceByName(aName, iism, getter_AddRefs(unused), getter_AddRefs(info));
00229   if (NS_FAILED(rv)) {
00230     return rv;
00231   }
00232 
00233   return aSet->AppendExternalInterface(info, aIndex);
00234 }
00235 
00236 /***************************************************************************/
00237 // AppendStandardInterface is used to 'seed' the generic info set with a
00238 // specific interface info that we expect to find in the super manager keyed 
00239 // by interface id.
00240  
00241 static nsresult
00242 AppendStandardInterface(const nsIID& iid, nsIInterfaceInfoSuperManager* iism,
00243                         nsIGenericInterfaceInfoSet* set, PRUint16* aIndex)
00244 {
00245   nsresult rv;
00246   nsCOMPtr<nsIInterfaceInfo> tempInfo;
00247 
00248   rv = iism->GetInfoForIID(&iid, getter_AddRefs(tempInfo));
00249   if (NS_FAILED(rv)) {
00250     return rv;
00251   }
00252 
00253   return set->AppendExternalInterface(tempInfo, aIndex);
00254 }
00255 
00256 /***************************************************************************/
00257 // BuildInterfaceName is used to construct the name of an interface
00258 // based on three AStrings.
00259 
00260 static void
00261 BuildInterfaceName(const nsAString& qualifier, const nsAString& name,
00262                    const nsAString& uri, nsACString& aCIdentifier)
00263 {
00264   WSPFactory::XML2C(qualifier, aCIdentifier);
00265 
00266   nsCAutoString temp;
00267   WSPFactory::XML2C(name, temp);
00268   aCIdentifier.Append(temp);
00269 
00270   WSPFactory::XML2C(uri, temp);
00271   aCIdentifier.Append(temp);
00272 }
00273 
00274 /***************************************************************************/
00275 // Forward declaration...
00276 
00277 static nsresult
00278 AppendMethodsForModelGroup(nsIInterfaceInfoSuperManager* iism,
00279                            nsIGenericInterfaceInfoSet* aSet,
00280                            nsISchemaModelGroup* aModelGroup,
00281                            const IIDX& iidx, XPTParamDescriptor* defaultResult,
00282                            nsIGenericInterfaceInfo* aInfo,
00283                            const nsAString& qualifier);
00284 
00285 // Forward declaration...
00286 static nsresult
00287 GetParamDescOfType(nsIInterfaceInfoSuperManager* iism,
00288                    nsIGenericInterfaceInfoSet* aSet,
00289                    nsISchemaType* aType, const IIDX& iidx,
00290                    XPTParamDescriptor* defaultResult,
00291                    const nsAString& qualifier, PRUint32 depth,
00292                    ParamAccumulator* aParams);
00293 
00294 /***************************************************************************/
00295 // AppendMethodForParticle appends a method to a 'struct' interface 
00296 // to represent the given nsISchemaParticle. It knows how to flatten
00297 // particles that are themselves modelgroups (by recurring into 
00298 // AppendMethodsForModelGroup). At also knows how to deal with arrays.
00299 
00300 static nsresult
00301 AppendMethodForParticle(nsIInterfaceInfoSuperManager* iism,
00302                         nsIGenericInterfaceInfoSet* aSet,
00303                         nsISchemaParticle* aParticle, const IIDX& iidx,
00304                         XPTParamDescriptor* defaultResult,
00305                         nsIGenericInterfaceInfo* aInfo,
00306                         const nsAString& qualifier)
00307 {
00308   nsresult rv;
00309   XPTMethodDescriptor methodDesc;
00310   XPTParamDescriptor* pparamDesc;
00311   PRUint16 ignoredIndex;
00312   XPTParamDescriptor* paramArray;
00313   ParamAccumulator params;
00314   PRUint16 i;
00315 
00316   // If the particle is itself a modelGroup, then flatten in its methods.
00317   nsCOMPtr<nsISchemaModelGroup> modelGroup(do_QueryInterface(aParticle));
00318   if (modelGroup) {
00319     return AppendMethodsForModelGroup(iism, aSet, modelGroup, iidx, 
00320                                       defaultResult, aInfo, qualifier);
00321   }
00322   // else...
00323 
00324   nsCOMPtr<nsISchemaElement> schemaElement(do_QueryInterface(aParticle));
00325   if (!schemaElement) {
00326     // XXX we are considering this an error. (e.g is a nsISchemaAnyParticle).
00327     // XXX need better error tracking!
00328     return NS_ERROR_UNEXPECTED;
00329   }
00330 
00331   nsCOMPtr<nsISchemaType> schemaType;
00332   schemaElement->GetType(getter_AddRefs(schemaType));
00333   if (!schemaType) {
00334     // XXX need better error tracking!
00335     return NS_ERROR_UNEXPECTED;
00336   }
00337 
00338   nsAutoString name;
00339   rv = aParticle->GetName(name);
00340   if (NS_FAILED(rv)) {
00341     return rv;
00342   }
00343 
00344   nsCAutoString identifierName;
00345   WSPFactory::XML2C(name, identifierName);
00346 
00347   rv = GetParamDescOfType(iism, aSet, schemaType, iidx, defaultResult,
00348                           qualifier, 0, &params);
00349   if (NS_FAILED(rv)) {
00350     return rv;
00351   }
00352 
00353   rv = aSet->AllocateParamArray(params.GetCount(), &paramArray);
00354   if (NS_FAILED(rv)) {
00355     return rv;
00356   }
00357 
00358   pparamDesc = params.GetArray();
00359   for (i = 0; i < params.GetCount(); pparamDesc++, i++) {
00360     // handle AString 'out' passing convensions
00361     pparamDesc->flags |=
00362       (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_DOMSTRING) ?
00363           (XPT_PD_IN | XPT_PD_DIPPER) : XPT_PD_OUT;
00364 
00365     // handle array size_of/length_of.
00366     if (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_ARRAY) {
00367       pparamDesc->type.argnum = 
00368           pparamDesc->type.argnum2 = i - 1; 
00369     }
00370     
00371     // handle trailing retval.
00372     if (i+1 == params.GetCount()) {
00373       pparamDesc->flags |= XPT_PD_RETVAL;
00374     }
00375   }
00376 
00377   memcpy(paramArray, params.GetArray(), 
00378          params.GetCount() * sizeof(XPTParamDescriptor));
00379 
00380   // XXX conditionally tack on 'Get' for array getter?
00381   // XXX Deal with intercaps in that case?
00382 
00383   methodDesc.flags    = params.GetCount() == 1 ? XPT_MD_GETTER : 0;
00384   methodDesc.name     = NS_CONST_CAST(char*, identifierName.get());
00385   methodDesc.params   = paramArray;
00386   methodDesc.result   = defaultResult;
00387   methodDesc.num_args = (PRUint8) params.GetCount();
00388 
00389   return aInfo->AppendMethod(&methodDesc, &ignoredIndex);
00390 }
00391 
00392 /***************************************************************************/
00393 // AppendMethodsForModelGroup iterates the group's particles and calls 
00394 // AppendMethodForParticle for each.
00395 
00396 static nsresult
00397 AppendMethodsForModelGroup(nsIInterfaceInfoSuperManager* iism,
00398                            nsIGenericInterfaceInfoSet* aSet,
00399                            nsISchemaModelGroup* aModelGroup,
00400                            const IIDX& iidx, XPTParamDescriptor* defaultResult,
00401                            nsIGenericInterfaceInfo* aInfo,
00402                            const nsAString& qualifier)
00403 {
00404   nsresult rv;
00405   PRUint32 particleCount;
00406   rv = aModelGroup->GetParticleCount(&particleCount);
00407   if (NS_FAILED(rv)) {
00408     return rv;
00409   }
00410 
00411   for (PRUint32 i = 0; i < particleCount; i++) {
00412     nsCOMPtr<nsISchemaParticle> particle;
00413     rv = aModelGroup->GetParticle(i, getter_AddRefs(particle));
00414     if (NS_FAILED(rv)) {
00415       return rv;
00416     }
00417 
00418     rv = AppendMethodForParticle(iism, aSet, particle, iidx, defaultResult,
00419                                  aInfo, qualifier);
00420     if (NS_FAILED(rv)) {
00421       return rv;
00422     }
00423   }
00424   return NS_OK;
00425 }
00426 
00427 /***************************************************************************/
00428 // FindOrConstructInterface is used for 'struct' interfaces that represent
00429 // compound data. Like the names says, it will find an existing info or
00430 // create one. In our world these 'struct' interfaces are discovered by
00431 // name: qualifier+typename+typetargetnamespace.
00432 
00433 static nsresult
00434 FindOrConstructInterface(nsIInterfaceInfoSuperManager* iism,
00435                          nsIGenericInterfaceInfoSet* aSet,
00436                          nsISchemaComplexType* aComplexType,
00437                          nsISchemaModelGroup* aModelGroup,
00438                          const IIDX& iidx, XPTParamDescriptor* defaultResult,
00439                          const nsAString& qualifier,
00440                          PRUint16* aTypeIndex)
00441 {
00442   nsresult rv;
00443   nsCAutoString qualifiedName;
00444   nsAutoString name;
00445   nsAutoString ns;
00446   nsCOMPtr<nsIGenericInterfaceInfo> newInfo;
00447   nsID tempID;
00448   PRBool haveUniqueID = PR_FALSE;
00449   
00450   rv = aComplexType->GetName(name);
00451   if (NS_FAILED(rv)) {
00452     return rv;
00453   }
00454 
00455   if (name.IsEmpty()) {
00456     // Fabricate a unique name for anonymous type.
00457     // Bug 199555
00458     ::NewUniqueID(&tempID);
00459     nsXPIDLCString idStr;
00460     idStr += tempID.ToString();
00461     name.AssignWithConversion(idStr);
00462     haveUniqueID = PR_TRUE;
00463   }
00464   else {
00465    rv = aComplexType->GetTargetNamespace(ns);
00466     if (NS_FAILED(rv)) {
00467       return rv;
00468     }
00469   }
00470 
00471   BuildInterfaceName(qualifier, name, ns, qualifiedName);
00472 
00473   // Does the interface already exist?
00474 
00475   rv = FindInterfaceIndexByName(qualifiedName.get(), iism, aSet, aTypeIndex);
00476   if (NS_SUCCEEDED(rv)) {
00477     return NS_OK;
00478   }
00479 
00480   // Need to create the interface.
00481 
00482   if (!haveUniqueID)
00483     ::NewUniqueID(&tempID);
00484   rv = aSet->CreateAndAppendInterface(qualifiedName.get(), tempID,
00485                                       iidx.Get(IIDX::IDX_nsISupports),
00486                                       XPT_ID_SCRIPTABLE,
00487                                       getter_AddRefs(newInfo),
00488                                       aTypeIndex);
00489   if (NS_FAILED(rv)) {
00490     return rv;
00491   }
00492 
00493   return AppendMethodsForModelGroup(iism, aSet, aModelGroup, iidx, 
00494                                     defaultResult, newInfo, qualifier);
00495 }
00496 
00497 /***************************************************************************/
00498 // GetParamDescOfType fills in a param descriptor for a given schematype.
00499 // The descriptor is appended to the ParamAccumulator passed in. In array cases
00500 // it may append more than one param. For compound data it may do significant
00501 // work (via FindOrConstructInterface). It is used both for populating the
00502 // params of the primary interface and of 'struct' interfaces.
00503 // Note that the flags that control param passing (such as XPT_PD_IN, 
00504 // XPT_PD_OUT, XPT_PD_DIPPER, and XPT_PD_RETVAL) are *not* set by this method.
00505 
00506 static nsresult
00507 GetParamDescOfType(nsIInterfaceInfoSuperManager* iism,
00508                    nsIGenericInterfaceInfoSet* aSet, nsISchemaType* aType,
00509                    const IIDX& iidx, XPTParamDescriptor* defaultResult,
00510                    const nsAString& qualifier, PRUint32 depth,
00511                    ParamAccumulator* aParams)
00512 {
00513   XPTTypeDescriptor* additionalType;
00514   PRUint16 typeIndex;
00515 
00516   nsCOMPtr<nsISchemaSimpleType> simpleType;
00517   nsresult rv;
00518 
00519   XPTParamDescriptor* paramDesc = aParams->GetNextParam();
00520   if (!paramDesc) {
00521     return NS_ERROR_OUT_OF_MEMORY;
00522   }
00523 
00524   nsCOMPtr<nsISchemaComplexType> complexType(do_QueryInterface(aType));
00525   if (complexType) {
00526     PRUint16 contentModel;
00527     rv = complexType->GetContentModel(&contentModel);
00528     if (NS_FAILED(rv)) {
00529       return rv;
00530     }
00531 
00532     PRBool isArray;
00533     rv = complexType->GetIsArray(&isArray);
00534     if (NS_FAILED(rv)) {
00535       return rv;
00536     }
00537 
00538     if (isArray) {
00539       // Punt by calling this array an nsIVariant.
00540       // Fix bug 202485
00541       paramDesc->type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
00542       paramDesc->type.type.iface = iidx.Get(IIDX::IDX_nsIVariant);
00543       return NS_OK;
00544     }
00545 
00546     switch(contentModel) {
00547       case nsISchemaComplexType::CONTENT_MODEL_SIMPLE:
00548         rv = complexType->GetSimpleBaseType(getter_AddRefs(simpleType));
00549         if (NS_FAILED(rv)) {
00550           return rv;
00551         }
00552         goto do_simple;
00553       case nsISchemaComplexType::CONTENT_MODEL_ELEMENT_ONLY:
00554       case nsISchemaComplexType::CONTENT_MODEL_MIXED:
00555         break;
00556       default:
00557         NS_ERROR("unexpected contentModel!");
00558       case nsISchemaComplexType::CONTENT_MODEL_EMPTY:
00559         return NS_ERROR_UNEXPECTED;
00560     }
00561 
00562     nsCOMPtr<nsISchemaModelGroup> modelGroup;
00563     rv = complexType->GetModelGroup(getter_AddRefs(modelGroup));
00564     if (NS_FAILED(rv)) {
00565       return rv;
00566     }
00567 
00568     PRUint16 compositor;
00569     rv = modelGroup->GetCompositor(&compositor);
00570     if (NS_FAILED(rv)) {
00571       return rv;
00572     }
00573 
00574     if (compositor == nsISchemaModelGroup::COMPOSITOR_CHOICE) {
00575       // CHOICE not supported
00576       return NS_ERROR_UNEXPECTED;
00577     }
00578 
00579     // XXX I *think* we can safely assume that we've already handled the case
00580     // where the type is an array.
00581 
00582     rv = FindOrConstructInterface(iism, aSet, complexType, modelGroup, iidx, 
00583                                   defaultResult, qualifier, &typeIndex);
00584     if (NS_FAILED(rv)) {
00585       return rv;
00586     }
00587 
00588     paramDesc->type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
00589     paramDesc->type.type.iface = typeIndex;
00590     return NS_OK;
00591   }
00592 
00593   // If it is not complex it *must* be simple.
00594 
00595   simpleType = do_QueryInterface(aType, &rv);
00596 do_simple:
00597   if (!simpleType) {
00598     return rv;
00599   }
00600 
00601   // We just ignore the restrictions on restrictionTypes and get at the
00602   // underlying simple type.
00603 
00604   nsCOMPtr<nsISchemaRestrictionType> restrictionType;
00605   while (nsnull != (restrictionType = do_QueryInterface(simpleType))) {
00606     rv = restrictionType->GetBaseType(getter_AddRefs(simpleType));
00607     if (NS_FAILED(rv)) {
00608       return rv;
00609     }
00610   }
00611 
00612   nsCOMPtr<nsISchemaBuiltinType> builtinType(do_QueryInterface(simpleType));
00613   if (builtinType) {
00614     PRUint16 typeID;
00615     rv = builtinType->GetBuiltinType(&typeID);
00616     if (NS_FAILED(rv)) {
00617       return rv;
00618     }
00619 
00620     switch(typeID) {
00621       case nsISchemaBuiltinType::BUILTIN_TYPE_ANYTYPE:
00622         paramDesc->type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
00623         paramDesc->type.type.iface = iidx.Get(IIDX::IDX_nsIVariant);
00624         return NS_OK;
00625       case nsISchemaBuiltinType::BUILTIN_TYPE_STRING:
00626       case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
00627       case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
00628         paramDesc->type.prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
00629         return NS_OK;
00630       case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
00631         paramDesc->type.prefix.flags = TD_INT8;
00632         return NS_OK;
00633       case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
00634         paramDesc->type.prefix.flags = TD_UINT8;
00635         return NS_OK;
00636       case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY:
00637       case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY:
00638         // XXX We are treating this as an array of TD_UINT8.
00639 
00640         rv = aSet->AllocateAdditionalType(&typeIndex, &additionalType);
00641         if (NS_FAILED(rv)) {
00642           return rv;
00643         }
00644 
00645         // Copy the element type into the referenced additional type.
00646         additionalType->prefix.flags = TD_UINT8;
00647 
00648         // Add the leading 'length' param.
00649         paramDesc->type.prefix.flags = TD_UINT32;
00650       
00651         // Alloc another param descriptor to hold the array info.
00652         paramDesc = aParams->GetNextParam();
00653         if (!paramDesc) {
00654           return NS_ERROR_OUT_OF_MEMORY;
00655         }
00656 
00657         // Set this *second* param as an array and return.
00658         paramDesc->type.prefix.flags = TD_ARRAY | XPT_TDP_POINTER;
00659         paramDesc->type.type.additional_type = typeIndex;
00660         return NS_OK;
00661       case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
00662       case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
00663         // XXX need a longInteger class?
00664         paramDesc->type.prefix.flags = TD_UINT64;
00665         return NS_OK;
00666       case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
00667       case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
00668       case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
00669         // XXX need a longInteger class?
00670         paramDesc->type.prefix.flags = TD_INT64;
00671         return NS_OK;
00672       case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
00673         paramDesc->type.prefix.flags = TD_INT32;
00674         return NS_OK;
00675       case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
00676         paramDesc->type.prefix.flags = TD_UINT32;
00677         return NS_OK;
00678       case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
00679         paramDesc->type.prefix.flags = TD_INT64;
00680         return NS_OK;
00681       case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
00682         paramDesc->type.prefix.flags = TD_UINT64;
00683         return NS_OK;
00684       case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
00685         paramDesc->type.prefix.flags = TD_INT16;
00686         return NS_OK;
00687       case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
00688         paramDesc->type.prefix.flags = TD_UINT16;
00689         return NS_OK;
00690       case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL:
00691         // XXX need a decimal class?
00692         paramDesc->type.prefix.flags = TD_DOUBLE;
00693         return NS_OK;
00694       case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT:
00695         paramDesc->type.prefix.flags = TD_FLOAT;
00696         return NS_OK;
00697       case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE:
00698         paramDesc->type.prefix.flags = TD_DOUBLE;
00699         return NS_OK;
00700       case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN:
00701         paramDesc->type.prefix.flags = TD_BOOL;
00702         return NS_OK;
00703       case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME:
00704         // XXX date type?
00705       case nsISchemaBuiltinType::BUILTIN_TYPE_TIME:
00706       case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION:
00707       case nsISchemaBuiltinType::BUILTIN_TYPE_DATE:
00708       case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH:
00709       case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR:
00710       case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH:
00711       case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY:
00712       case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY:
00713         paramDesc->type.prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
00714         return NS_OK;
00715 
00716       case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
00717       case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME:
00718       case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
00719       case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI:
00720       case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
00721       case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
00722       case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
00723       case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
00724       case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
00725       case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
00726       case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION:
00727       case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
00728       case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
00729         paramDesc->type.prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
00730         return NS_OK;
00731 
00732       default:
00733         NS_ERROR("unexpected typeID!");
00734         return NS_ERROR_UNEXPECTED;
00735     }
00736     NS_ERROR("missing return");
00737     return NS_ERROR_UNEXPECTED;
00738   }
00739 
00740   // else...
00741 
00742   nsCOMPtr<nsISchemaListType> listType(do_QueryInterface(simpleType));
00743   if (listType) {
00744     paramDesc->type.prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
00745     return NS_OK;
00746   }
00747 
00748   // else...
00749 
00750   nsCOMPtr<nsISchemaUnionType> unionType(do_QueryInterface(simpleType));
00751   if (unionType) {
00752     paramDesc->type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
00753     paramDesc->type.type.iface = iidx.Get(IIDX::IDX_nsIVariant);
00754     return NS_OK;
00755   }
00756 
00757   // else...
00758 
00759   NS_ERROR("unexpected simple type!");
00760   return NS_ERROR_UNEXPECTED;
00761 }
00762 
00763 /***************************************************************************/
00764 // GetParamDescOfPart is used in building the primary interface. It figures
00765 // out if encoding of a given param is even necessary and then finds the
00766 // appropriate schema type so that it can call GetParamDescOfType to do the
00767 // rest of the work of filliung in a param descriptor.
00768 
00769 static nsresult
00770 GetParamDescOfPart(nsIInterfaceInfoSuperManager* iism,
00771                    nsIGenericInterfaceInfoSet* aSet, nsIWSDLPart* aPart,
00772                    const IIDX& iidx, XPTParamDescriptor* defaultResult,
00773                    const nsAString& qualifier, ParamAccumulator* aParams)
00774 {
00775   nsresult rv;
00776 
00777   // If the binding is 'literal' then we consider this as DOM element.
00778   nsCOMPtr<nsIWSDLBinding> binding;
00779   rv = aPart->GetBinding(getter_AddRefs(binding));
00780   if (NS_FAILED(rv)) {
00781     return rv;
00782   }
00783 
00784   nsCOMPtr<nsISOAPPartBinding> soapPartBinding(do_QueryInterface(binding));
00785   if (soapPartBinding) {
00786     PRUint16 use;
00787     rv = soapPartBinding->GetUse(&use);
00788     if (NS_FAILED(rv)) {
00789       return rv;
00790     }
00791 
00792     if (use == nsISOAPPartBinding::USE_LITERAL) {
00793       XPTParamDescriptor* paramDesc = aParams->GetNextParam();
00794       if (!paramDesc) {
00795         return NS_ERROR_OUT_OF_MEMORY;
00796       }
00797       paramDesc->type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
00798       paramDesc->type.type.iface = iidx.Get(IIDX::IDX_nsIDOMElement);
00799       return NS_OK;
00800     }
00801   }
00802 
00803   nsCOMPtr<nsISchemaComponent> schemaComponent;
00804   rv = aPart->GetSchemaComponent(getter_AddRefs(schemaComponent));
00805   if (NS_FAILED(rv)) {
00806     return rv;
00807   }
00808 
00809   nsCOMPtr<nsISchemaType> type;
00810   nsCOMPtr<nsISchemaElement> element(do_QueryInterface(schemaComponent));
00811   if (element) {
00812     rv = element->GetType(getter_AddRefs(type));
00813   }
00814   else {
00815     type = do_QueryInterface(schemaComponent, &rv);
00816   }
00817 
00818   if (NS_FAILED(rv)) {
00819     return rv;
00820   }
00821 
00822   return GetParamDescOfType(iism, aSet, type, iidx, defaultResult, qualifier,
00823                             0, aParams);
00824 }
00825 
00826 /***************************************************************************/
00827 // AccumulateParamsForMessage iterates the parts of a given message and
00828 // accumulates the param descriptors.
00829 
00830 static nsresult
00831 AccumulateParamsForMessage(nsIInterfaceInfoSuperManager* iism,
00832                            nsIGenericInterfaceInfoSet* aSet,
00833                            nsIWSDLMessage* aMsg, const IIDX& iidx,
00834                            XPTParamDescriptor* defaultResult,
00835                            const nsAString& qualifier,
00836                            ParamAccumulator* aParams)
00837 {
00838   nsresult rv;
00839   PRUint32 partCount;
00840   
00841   rv = aMsg->GetPartCount(&partCount);
00842   if (NS_FAILED(rv)) {
00843     return rv;
00844   }
00845 
00846   for (PRUint32 i = 0; i < partCount; i++) {
00847     nsCOMPtr<nsIWSDLPart> part;
00848     rv = aMsg->GetPart(i, getter_AddRefs(part));
00849     if (NS_FAILED(rv)) {
00850       return rv;
00851     }
00852 
00853     // Accumulate paramDescriptors (except some flags). This might include
00854     // constructing a nested set of compound types and adding them
00855     // to the set.
00856 
00857     rv = GetParamDescOfPart(iism, aSet, part, iidx, defaultResult, qualifier,
00858                             aParams);
00859     if (NS_FAILED(rv)) {
00860       return rv;
00861     }
00862   }
00863   return NS_OK;
00864 }  
00865 
00866 /***************************************************************************/
00867 
00868 NS_IMPL_ISUPPORTS1(nsWSPInterfaceInfoService, nsIWSPInterfaceInfoService)
00869 
00870 nsWSPInterfaceInfoService::nsWSPInterfaceInfoService()
00871 {
00872 }
00873 
00874 nsWSPInterfaceInfoService::~nsWSPInterfaceInfoService()
00875 {
00876   // empty
00877 }
00878 
00879 /***************************************************************************/
00880 // InfoForPort takes a nsIWSDLPort, qualifier name, and isAsync flag and
00881 // finds or constructs the primary interface info for that port. It also
00882 // finds or constructs all the interface infos used in params to its methods.
00883 // It returns the interface info and optionally the interface info set - 
00884 // which allows the caller to gather information on the referenced interfaces. 
00885 
00886 /* nsIInterfaceInfo infoForPort (in nsIWSDLPort aPort, in AString
00887    aPortURL, in AString aQualifier, in PRBool aIsAsync, out
00888    nsIInterfaceInfoManager aSet); */
00889 NS_IMETHODIMP
00890 nsWSPInterfaceInfoService::InfoForPort(nsIWSDLPort *aPort,
00891                                        const nsAString & aPortURL,
00892                                        const nsAString & aQualifier,
00893                                        PRBool aIsAsync,
00894                                        nsIInterfaceInfoManager **aSet,
00895                                        nsIInterfaceInfo **_retval)
00896 {
00897   if (!aPort) {
00898     // aPort can't be null.
00899     return NS_ERROR_NULL_POINTER;
00900   }
00901 
00902   nsresult rv;
00903 
00904   nsCAutoString primaryName;
00905   nsCAutoString primaryAsyncName;
00906   nsAutoString portName;
00907 
00908   nsCOMPtr<nsIInterfaceInfoSuperManager> iism =
00909     do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID);
00910   if (!iism) {
00911     return NS_ERROR_UNEXPECTED;
00912   }
00913 
00914   // Build the primary and primaryAsync interface names.
00915 
00916   rv = aPort->GetName(portName);
00917   if (NS_FAILED(rv)) {
00918     return rv;
00919   }
00920 
00921   BuildInterfaceName(aQualifier, portName, aPortURL, primaryName);
00922   primaryAsyncName.Assign(primaryName);
00923   primaryAsyncName.Append("Async");
00924 
00925   // With luck the work has already been done and we can just return the
00926   // existing info.
00927 
00928   if (NS_SUCCEEDED(FindInterfaceByName(aIsAsync ? primaryAsyncName.get() :
00929                                                   primaryName.get(),
00930                                        iism, aSet, _retval))) {
00931     return NS_OK;
00932   }
00933 
00934   // No, we need to build all the stuff...
00935 
00936   nsCOMPtr<nsIGenericInterfaceInfo> primaryInfo;
00937   nsCOMPtr<nsIGenericInterfaceInfo> primaryAsyncInfo;
00938   nsCOMPtr<nsIGenericInterfaceInfo> listenerInfo;
00939 
00940   ParamAccumulator inParams;
00941   ParamAccumulator outParams;
00942 
00943   XPTParamDescriptor* tempParamArray;
00944   XPTParamDescriptor* defaultResult;
00945 
00946   XPTParamDescriptor* primaryParamArray;
00947   XPTParamDescriptor* primaryAsyncParamArray;
00948   XPTParamDescriptor* listenerParamArray;
00949 
00950   nsCOMPtr<nsIInterfaceInfo> tempInfo;
00951   nsCAutoString tempCString;
00952   nsAutoString tempString;
00953 
00954   IIDX iidx;
00955   PRUint16 listenerIndex;
00956 
00957   XPTMethodDescriptor methodDesc;
00958   XPTParamDescriptor paramDesc;
00959   XPTParamDescriptor* pparamDesc;
00960 
00961   // Create a new info set.
00962 
00963   nsCOMPtr<nsIGenericInterfaceInfoSet> set =
00964     do_CreateInstance(NS_GENERIC_INTERFACE_INFO_SET_CONTRACTID, &rv);
00965   if (NS_FAILED(rv)) {
00966     return rv;
00967   }
00968 
00969   // Seed the info set with commonly needed interfaces.
00970 
00971   rv = AppendStandardInterface(NS_GET_IID(nsISupports), iism, set,
00972                                iidx.GetAddr(IIDX::IDX_nsISupports));
00973   if (NS_FAILED(rv)) {
00974     return rv;
00975   }
00976 
00977   rv = AppendStandardInterface(NS_GET_IID(nsIException), iism, set,
00978                                iidx.GetAddr(IIDX::IDX_nsIException));
00979   if (NS_FAILED(rv)) {
00980     return rv;
00981   }
00982 
00983   rv = AppendStandardInterface(NS_GET_IID(nsIWebServiceCallContext), iism, set,
00984                                iidx.GetAddr(IIDX::IDX_nsIWebServiceCallContext));
00985   if (NS_FAILED(rv)) {
00986     return rv;
00987   }
00988 
00989   rv = AppendStandardInterface(NS_GET_IID(nsIVariant), iism, set,
00990                                iidx.GetAddr(IIDX::IDX_nsIVariant));
00991   if (NS_FAILED(rv)) {
00992     return rv;
00993   }
00994 
00995   rv = AppendStandardInterface(NS_GET_IID(nsIDOMElement), iism, set,
00996                                iidx.GetAddr(IIDX::IDX_nsIDOMElement));
00997   if (NS_FAILED(rv)) {
00998     return rv;
00999   }
01000 
01001   // Create and add the primary interface.
01002 
01003   PRUint16 ignoredIndex;
01004   nsID tempID;
01005 
01006   ::NewUniqueID(&tempID);
01007   rv = set->CreateAndAppendInterface(primaryName.get(), tempID,
01008                                      iidx.Get(IIDX::IDX_nsISupports),
01009                                      XPT_ID_SCRIPTABLE,
01010                                      getter_AddRefs(primaryInfo),
01011                                      &ignoredIndex);
01012   if (NS_FAILED(rv)) {
01013     return rv;
01014   }
01015 
01016   // Create and add the primary async interface.
01017 
01018   ::NewUniqueID(&tempID);
01019   rv = set->CreateAndAppendInterface(primaryAsyncName.get(), tempID,
01020                                      iidx.Get(IIDX::IDX_nsISupports),
01021                                      XPT_ID_SCRIPTABLE,
01022                                      getter_AddRefs(primaryAsyncInfo),
01023                                      &ignoredIndex);
01024   if (NS_FAILED(rv)) {
01025     return rv;
01026   }
01027 
01028 
01029   // Allocate the param info for the 'nsresult' return type that we reuse.
01030 
01031   rv = set->AllocateParamArray(1, &defaultResult);
01032   if (NS_FAILED(rv)) {
01033     return rv;
01034   }
01035 
01036   defaultResult->type.prefix.flags = TD_UINT32;
01037   defaultResult->flags = XPT_PD_OUT;
01038 
01039   // Create and add the listener interface.
01040 
01041   tempCString = primaryName;
01042   tempCString.Append("Listener");
01043   ::NewUniqueID(&tempID);
01044   rv = set->CreateAndAppendInterface(tempCString.get(), tempID,
01045                                      iidx.Get(IIDX::IDX_nsISupports),
01046                                      XPT_ID_SCRIPTABLE,
01047                                      getter_AddRefs(listenerInfo),
01048                                      &listenerIndex);
01049   if (NS_FAILED(rv)) {
01050     return rv;
01051   }
01052 
01053   // Add the setListener method to the primaryAsync interface.
01054   // void setListener(in 'OurType'Listener listener);
01055 
01056   rv = set->AllocateParamArray(1, &tempParamArray);
01057   if (NS_FAILED(rv)) {
01058     return rv;
01059   }
01060 
01061   tempParamArray[0].type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
01062   tempParamArray[0].type.type.iface = listenerIndex;
01063   tempParamArray[0].flags = XPT_PD_IN;
01064   methodDesc.name     = "setListener";
01065   methodDesc.params   = tempParamArray;
01066   methodDesc.result   = defaultResult;
01067   methodDesc.flags    = 0;
01068   methodDesc.num_args = 1;
01069 
01070   rv = primaryAsyncInfo->AppendMethod(&methodDesc, &ignoredIndex);
01071   if (NS_FAILED(rv)) {
01072     return rv;
01073   }
01074 
01075   // Add the onError method to the listener interface.
01076   // void onError(in nsIException error, in nsIWebServiceCallContext cx);
01077 
01078   rv = set->AllocateParamArray(2, &tempParamArray);
01079   if (NS_FAILED(rv)) {
01080     return rv;
01081   }
01082 
01083   tempParamArray[0].type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
01084   tempParamArray[0].type.type.iface = iidx.Get(IIDX::IDX_nsIException);
01085   tempParamArray[0].flags = XPT_PD_IN;
01086 
01087   tempParamArray[1].type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
01088   tempParamArray[1].type.type.iface =
01089     iidx.Get(IIDX::IDX_nsIWebServiceCallContext);
01090   tempParamArray[1].flags = XPT_PD_IN;
01091 
01092   methodDesc.name     = "onError";
01093   methodDesc.params   = tempParamArray;
01094   methodDesc.result   = defaultResult;
01095   methodDesc.flags    = 0;
01096   methodDesc.num_args = 2;
01097 
01098   rv = listenerInfo->AppendMethod(&methodDesc, &ignoredIndex);
01099   if (NS_FAILED(rv)) {
01100     return rv;
01101   }
01102 
01103   // Add the methods.
01104 
01105   PRUint32 methodCount;
01106   rv = aPort->GetOperationCount(&methodCount);
01107   if (NS_FAILED(rv)) {
01108     return rv;
01109   }
01110 
01111   PRUint32 i;
01112   for (i = 0; i < methodCount; i++)
01113   {
01114     nsCOMPtr<nsIWSDLOperation> op;
01115     rv = aPort->GetOperation(i, getter_AddRefs(op));
01116     if (NS_FAILED(rv)) {
01117       return rv;
01118     }
01119 
01120     // Accumulate the input params.
01121 
01122     nsCOMPtr<nsIWSDLMessage> msg;
01123     rv = op->GetInput(getter_AddRefs(msg));
01124     if (NS_FAILED(rv)) {
01125       return rv;
01126     }
01127     
01128     inParams.Clear();
01129     rv = AccumulateParamsForMessage(iism, set, msg, iidx, defaultResult, 
01130                                     aQualifier, &inParams);
01131     if (NS_FAILED(rv)) {
01132       return rv;
01133     }
01134 
01135     // Accumulate the output params.
01136 
01137     rv = op->GetOutput(getter_AddRefs(msg));
01138     if (NS_FAILED(rv)) {
01139       return rv;
01140     }
01141 
01142     outParams.Clear();
01143     rv = AccumulateParamsForMessage(iism, set, msg, iidx, defaultResult, 
01144                                     aQualifier, &outParams);
01145     if (NS_FAILED(rv)) {
01146       return rv;
01147     }
01148 
01149     // XXX do we need types for the faults?
01150     // XXX ignoring param ordering problem for now.
01151 
01152     // Allocate the param arrays. On the other hand
01153     // no need to allocate the param arrays if the
01154     // input type and the output type are null; fixing
01155     // bug 200767
01156     PRUint32 k = 0;
01157     PRUint16 primaryParamCount = inParams.GetCount() + outParams.GetCount();
01158     if (primaryParamCount != 0) { 
01159       rv = set->AllocateParamArray(primaryParamCount, &primaryParamArray);
01160       if (NS_FAILED(rv)) {
01161         return rv;
01162       }
01163 
01164       // Set the appropriate 'in' param flags.
01165     
01166       // 'input' param cases are easy because they are exactly the same for
01167       // primary and primaryAsync.
01168 
01169       pparamDesc = inParams.GetArray();
01170 
01171       for (k = 0; k < inParams.GetCount(); pparamDesc++, k++) {
01172         // set direction flag
01173         pparamDesc->flags |= XPT_PD_IN;
01174 
01175         // handle array size_of/length_of.
01176         if (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_ARRAY) {
01177           pparamDesc->type.argnum = 
01178               pparamDesc->type.argnum2 = k - 1; 
01179         }
01180       }
01181         
01182       // Copy the 'in' param arrays.
01183 
01184       memcpy(primaryParamArray, inParams.GetArray(), 
01185              inParams.GetCount() * sizeof(XPTParamDescriptor));
01186     
01187       // Do 'output' param cases for primary interface.
01188 
01189       pparamDesc = outParams.GetArray();
01190       for (k = 0; k < outParams.GetCount(); pparamDesc++, k++) {
01191         // handle AString 'out' passing convensions
01192         pparamDesc->flags |=
01193           (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_DOMSTRING) ?
01194               (XPT_PD_IN | XPT_PD_DIPPER) : XPT_PD_OUT;
01195 
01196         // handle array size_of/length_of.
01197         if (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_ARRAY) {
01198           pparamDesc->type.argnum =
01199               pparamDesc->type.argnum2 = inParams.GetCount() + k - 1; 
01200         }
01201       
01202         // handle trailing retval.
01203         if (k+1 == outParams.GetCount()) {
01204           pparamDesc->flags |= XPT_PD_RETVAL;
01205         }
01206       }
01207 
01208       memcpy(primaryParamArray + inParams.GetCount(), 
01209              outParams.GetArray(), 
01210              outParams.GetCount() * sizeof(XPTParamDescriptor));
01211       // primaryParamArray is done now.
01212     }
01213 
01214 
01215     PRUint16 primaryAsyncParamCount = inParams.GetCount() + 1;
01216     rv = set->AllocateParamArray(primaryAsyncParamCount,
01217                                  &primaryAsyncParamArray);
01218     if (NS_FAILED(rv)) {
01219       return rv;
01220     }
01221 
01222     memcpy(primaryAsyncParamArray, inParams.GetArray(), 
01223            inParams.GetCount() * sizeof(XPTParamDescriptor));
01224 
01225 
01226     // Add the trailing [retval] param for the Async call
01227 
01228     paramDesc.type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
01229     paramDesc.type.type.iface = iidx.Get(IIDX::IDX_nsIWebServiceCallContext);
01230     paramDesc.flags = XPT_PD_OUT | XPT_PD_RETVAL;
01231     primaryAsyncParamArray[inParams.GetCount()] = paramDesc;
01232     // primaryAsyncParamArray is done now.
01233 
01234     PRUint16 listenerParamCount = 1 + outParams.GetCount();
01235     rv = set->AllocateParamArray(listenerParamCount, &listenerParamArray);
01236     if (NS_FAILED(rv)) {
01237       return rv;
01238     }
01239 
01240     // Do 'output' param cases for listener interface.
01241 
01242     pparamDesc = outParams.GetArray();
01243     for (k = 0; k < outParams.GetCount(); pparamDesc++, k++) {
01244       // set direction flag
01245       pparamDesc->flags &= ~(XPT_PD_OUT | XPT_PD_DIPPER | XPT_PD_RETVAL);
01246       pparamDesc->flags |= XPT_PD_IN;
01247     
01248       // handle array size_of/length_of.
01249       if (XPT_TDP_TAG(pparamDesc->type.prefix) == TD_ARRAY) {
01250         pparamDesc->type.argnum = 
01251             pparamDesc->type.argnum2 = k - 1;  
01252       }
01253     }
01254 
01255     memcpy(listenerParamArray, 
01256            outParams.GetArray(), 
01257            outParams.GetCount() * sizeof(XPTParamDescriptor));
01258 
01259     // Add the trailing 'in nsIWebServiceCallContext cx' param for listener
01260 
01261     paramDesc.type.prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER;
01262     paramDesc.type.type.iface = iidx.Get(IIDX::IDX_nsIWebServiceCallContext);
01263     paramDesc.flags = XPT_PD_IN;
01264     listenerParamArray[listenerParamCount-1] = paramDesc;
01265     // listenerParamArray is done now.
01266 
01267     rv = op->GetName(tempString);
01268     if (NS_FAILED(rv)) {
01269       return rv;
01270     }
01271 
01272     // Append the methods...
01273 
01274     WSPFactory::XML2C(tempString, tempCString);
01275 
01276     methodDesc.name     = NS_CONST_CAST(char*, tempCString.get());
01277     methodDesc.params   = primaryParamArray;
01278     methodDesc.result   = defaultResult;
01279     methodDesc.flags    = 0;
01280     methodDesc.num_args = (PRUint8) primaryParamCount;
01281 
01282     rv = primaryInfo->AppendMethod(&methodDesc, &ignoredIndex);
01283     if (NS_FAILED(rv)) {
01284       return rv;
01285     }
01286 
01287 
01288     methodDesc.name     = NS_CONST_CAST(char*, tempCString.get());
01289     methodDesc.params   = primaryAsyncParamArray;
01290     methodDesc.result   = defaultResult;
01291     methodDesc.flags    = 0;
01292     methodDesc.num_args = (PRUint8) primaryAsyncParamCount;
01293 
01294     rv = primaryAsyncInfo->AppendMethod(&methodDesc, &ignoredIndex);
01295     if (NS_FAILED(rv)) {
01296       return rv;
01297     }
01298 
01299 
01300     tempCString.Append("Callback");
01301     methodDesc.name     = NS_CONST_CAST(char*, tempCString.get());
01302     methodDesc.params   = listenerParamArray;
01303     methodDesc.result   = defaultResult;
01304     methodDesc.flags    = 0;
01305     methodDesc.num_args = (PRUint8) listenerParamCount;
01306 
01307     rv = listenerInfo->AppendMethod(&methodDesc, &ignoredIndex);
01308     if (NS_FAILED(rv)) {
01309       return rv;
01310     }
01311   }
01312 
01313   // 'Publish' our new set by adding it to the global additional managers list.
01314 
01315   rv = iism->AddAdditionalManager(set);
01316   if (NS_FAILED(rv)) {
01317     return rv;
01318   }
01319 
01320   // Optionally return our new set.
01321 
01322   if (aSet) {
01323     NS_ADDREF(*aSet = set);
01324   }
01325 
01326   // Return the appropriate interface info.
01327 
01328   if (aIsAsync) {
01329     NS_ADDREF(*_retval = primaryAsyncInfo);
01330   }
01331   else {
01332     NS_ADDREF(*_retval = primaryInfo);
01333   }
01334 
01335   return NS_OK;
01336 }
01337