Back to index

lightning-sunbird  0.9+nobinonly
xptiInterfaceInfo.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mike McCabe <mccabe@netscape.com>
00024  *   John Bandhauer <jband@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or 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 /* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */
00041 
00042 #include "xptiprivate.h"
00043 
00044 /***************************************************************************/
00045 // Debug Instrumentation...
00046 
00047 #ifdef SHOW_INFO_COUNT_STATS
00048 static int DEBUG_TotalInfos = 0;
00049 static int DEBUG_CurrentInfos = 0;
00050 static int DEBUG_MaxInfos = 0;
00051 static int DEBUG_MonitorEntryCount = 0;
00052 
00053 #define LOG_INFO_CREATE(t)                                                  \
00054     DEBUG_TotalInfos++;                                                     \
00055     DEBUG_CurrentInfos++;                                                   \
00056     if(DEBUG_MaxInfos < DEBUG_CurrentInfos)                                 \
00057         DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */
00058 
00059 #define LOG_INFO_DESTROY(t)                                                 \
00060     DEBUG_CurrentInfos-- /* no ';' */
00061 
00062 #define LOG_INFO_MONITOR_ENTRY                                              \
00063     DEBUG_MonitorEntryCount++ /* no ';' */
00064 
00065 #else /* SHOW_INFO_COUNT_STATS */
00066 
00067 #define LOG_INFO_CREATE(t)     ((void)0)
00068 #define LOG_INFO_DESTROY(t)    ((void)0)
00069 #define LOG_INFO_MONITOR_ENTRY ((void)0)
00070 #endif /* SHOW_INFO_COUNT_STATS */
00071 
00072 #ifdef DEBUG
00073 // static 
00074 void xptiInterfaceInfo::DEBUG_ShutdownNotification()
00075 {
00076 #ifdef SHOW_INFO_COUNT_STATS
00077     printf("iiii %d total xptiInterfaceInfos created\n", DEBUG_TotalInfos);      
00078     printf("iiii %d max xptiInterfaceInfos alive at one time\n", DEBUG_MaxInfos);       
00079     printf("iiii %d xptiInterfaceInfos still alive\n", DEBUG_CurrentInfos);       
00080     printf("iiii %d times locked\n", DEBUG_MonitorEntryCount);       
00081 #endif
00082 }
00083 #endif /* DEBUG */
00084 
00085 /***************************************************************************/
00086 
00087 // static 
00088 xptiInterfaceEntry* 
00089 xptiInterfaceEntry::NewEntry(const char* name,
00090                              int nameLength,
00091                              const nsID& iid,
00092                              const xptiTypelib& typelib,
00093                              xptiWorkingSet* aWorkingSet)
00094 {
00095     void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
00096                              sizeof(xptiInterfaceEntry) + nameLength);
00097     if(!place)
00098         return nsnull;
00099     return new(place) xptiInterfaceEntry(name, nameLength, iid, typelib);
00100 }
00101 
00102 // static 
00103 xptiInterfaceEntry* 
00104 xptiInterfaceEntry::NewEntry(const xptiInterfaceEntry& r,
00105                              const xptiTypelib& typelib,
00106                              xptiWorkingSet* aWorkingSet)
00107 {
00108     size_t nameLength = PL_strlen(r.mName);
00109     void* place = XPT_MALLOC(aWorkingSet->GetStructArena(),
00110                              sizeof(xptiInterfaceEntry) + nameLength);
00111     if(!place)
00112         return nsnull;
00113     return new(place) xptiInterfaceEntry(r, nameLength, typelib);
00114 }
00115 
00116 
00117 xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
00118                                        size_t nameLength,
00119                                        const nsID& iid,
00120                                        const xptiTypelib& typelib)
00121     :   mIID(iid),
00122         mTypelib(typelib),
00123         mInfo(nsnull),
00124         mFlags(uint8(0))
00125 {
00126     memcpy(mName, name, nameLength);
00127 }
00128 
00129 xptiInterfaceEntry::xptiInterfaceEntry(const xptiInterfaceEntry& r,
00130                                        size_t nameLength,
00131                                        const xptiTypelib& typelib)
00132     :   mIID(r.mIID),
00133         mTypelib(typelib),
00134         mInfo(nsnull),
00135         mFlags(r.mFlags)
00136 {
00137     SetResolvedState(NOT_RESOLVED);
00138     memcpy(mName, r.mName, nameLength);
00139 }
00140 
00141 PRBool 
00142 xptiInterfaceEntry::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */)
00143 {
00144     nsAutoLock lock(xptiInterfaceInfoManager::GetResolveLock());
00145     return ResolveLocked(aWorkingSet);
00146 }
00147 
00148 PRBool 
00149 xptiInterfaceEntry::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */)
00150 {
00151     int resolvedState = GetResolveState();
00152 
00153     if(resolvedState == FULLY_RESOLVED)
00154         return PR_TRUE;
00155     if(resolvedState == RESOLVE_FAILED)
00156         return PR_FALSE;
00157 
00158     xptiInterfaceInfoManager* mgr = 
00159         xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef();
00160 
00161     if(!mgr)
00162         return PR_FALSE;
00163 
00164     if(!aWorkingSet)
00165     {
00166         aWorkingSet = mgr->GetWorkingSet();
00167     }
00168 
00169     if(resolvedState == NOT_RESOLVED)
00170     {
00171         LOG_RESOLVE(("! begin    resolve of %s\n", mName));
00172         // Make a copy of mTypelib because the underlying memory will change!
00173         xptiTypelib typelib = mTypelib;
00174         
00175         // We expect our PartiallyResolveLocked() to get called before 
00176         // this returns. 
00177         if(!mgr->LoadFile(typelib, aWorkingSet))
00178         {
00179             SetResolvedState(RESOLVE_FAILED);
00180             return PR_FALSE;    
00181         }
00182         // The state was changed by LoadFile to PARTIALLY_RESOLVED, so this 
00183         // ...falls through...
00184     }
00185 
00186     NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!");    
00187 
00188     // Finish out resolution by finding parent and Resolving it so
00189     // we can set the info we get from it.
00190 
00191     PRUint16 parent_index = mInterface->mDescriptor->parent_interface;
00192 
00193     if(parent_index)
00194     {
00195         xptiInterfaceEntry* parent = 
00196             aWorkingSet->GetTypelibGuts(mInterface->mTypelib)->
00197                                 GetEntryAt(parent_index - 1);
00198         
00199         if(!parent || !parent->EnsureResolvedLocked())
00200         {
00201             xptiTypelib aTypelib = mInterface->mTypelib;
00202             mInterface = nsnull;
00203             mTypelib = aTypelib;
00204             SetResolvedState(RESOLVE_FAILED);
00205             return PR_FALSE;
00206         }
00207 
00208         mInterface->mParent = parent;
00209 
00210         mInterface->mMethodBaseIndex =
00211             parent->mInterface->mMethodBaseIndex + 
00212             parent->mInterface->mDescriptor->num_methods;
00213         
00214         mInterface->mConstantBaseIndex =
00215             parent->mInterface->mConstantBaseIndex + 
00216             parent->mInterface->mDescriptor->num_constants;
00217 
00218     }
00219     LOG_RESOLVE(("+ complete resolve of %s\n", mName));
00220 
00221     SetResolvedState(FULLY_RESOLVED);
00222     return PR_TRUE;
00223 }        
00224 
00225 // This *only* gets called by xptiInterfaceInfoManager::LoadFile (while locked).
00226 PRBool 
00227 xptiInterfaceEntry::PartiallyResolveLocked(XPTInterfaceDescriptor*  aDescriptor,
00228                                            xptiWorkingSet*          aWorkingSet)
00229 {
00230     NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state");
00231 
00232     LOG_RESOLVE(("~ partial  resolve of %s\n", mName));
00233 
00234     xptiInterfaceGuts* iface = 
00235         xptiInterfaceGuts::NewGuts(aDescriptor, mTypelib, aWorkingSet);
00236 
00237     if(!iface)
00238         return PR_FALSE;
00239 
00240     mInterface = iface;
00241 
00242 #ifdef DEBUG
00243     if(!DEBUG_ScriptableFlagIsValid())
00244     {
00245         NS_ERROR("unexpected scriptable flag!");
00246         SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags));
00247     }
00248 #endif
00249 
00250     SetResolvedState(PARTIALLY_RESOLVED);
00251     return PR_TRUE;
00252 }        
00253 
00254 /**************************************************/
00255 // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
00256 
00257 nsresult
00258 xptiInterfaceEntry::GetName(char **name)
00259 {
00260     // It is not necessary to Resolve because this info is read from manifest.
00261     *name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1);
00262     return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00263 }
00264 
00265 nsresult
00266 xptiInterfaceEntry::GetIID(nsIID **iid)
00267 {
00268     // It is not necessary to Resolve because this info is read from manifest.
00269     *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
00270     return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00271 }
00272 
00273 nsresult
00274 xptiInterfaceEntry::IsScriptable(PRBool* result)
00275 {
00276     // It is not necessary to Resolve because this info is read from manifest.
00277     NS_ASSERTION(DEBUG_ScriptableFlagIsValid(), "scriptable flag out of sync!");   
00278     *result = GetScriptableFlag();
00279     return NS_OK;
00280 }
00281 
00282 nsresult
00283 xptiInterfaceEntry::IsFunction(PRBool* result)
00284 {
00285     if(!EnsureResolved())
00286         return NS_ERROR_UNEXPECTED;
00287 
00288     *result = XPT_ID_IS_FUNCTION(GetInterfaceGuts()->mDescriptor->flags);
00289     return NS_OK;
00290 }
00291 
00292 nsresult
00293 xptiInterfaceEntry::GetMethodCount(uint16* count)
00294 {
00295     if(!EnsureResolved())
00296         return NS_ERROR_UNEXPECTED;
00297     
00298     *count = mInterface->mMethodBaseIndex + 
00299              mInterface->mDescriptor->num_methods;
00300     return NS_OK;
00301 }
00302 
00303 nsresult
00304 xptiInterfaceEntry::GetConstantCount(uint16* count)
00305 {
00306     if(!EnsureResolved())
00307         return NS_ERROR_UNEXPECTED;
00308 
00309     *count = mInterface->mConstantBaseIndex + 
00310              mInterface->mDescriptor->num_constants;
00311     return NS_OK;
00312 }
00313 
00314 nsresult
00315 xptiInterfaceEntry::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info)
00316 {
00317     if(!EnsureResolved())
00318         return NS_ERROR_UNEXPECTED;
00319 
00320     if(index < mInterface->mMethodBaseIndex)
00321         return mInterface->mParent->GetMethodInfo(index, info);
00322 
00323     if(index >= mInterface->mMethodBaseIndex + 
00324                 mInterface->mDescriptor->num_methods)
00325     {
00326         NS_ERROR("bad param");
00327         *info = NULL;
00328         return NS_ERROR_INVALID_ARG;
00329     }
00330 
00331     // else...
00332     *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*,
00333                                 &mInterface->mDescriptor->
00334                                     method_descriptors[index - 
00335                                         mInterface->mMethodBaseIndex]);
00336     return NS_OK;
00337 }
00338 
00339 nsresult
00340 xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16 *index,
00341                                          const nsXPTMethodInfo** result)
00342 {
00343     if(!EnsureResolved())
00344         return NS_ERROR_UNEXPECTED;
00345 
00346     // This is a slow algorithm, but this is not expected to be called much.
00347     for(uint16 i = 0; i < mInterface->mDescriptor->num_methods; ++i)
00348     {
00349         const nsXPTMethodInfo* info;
00350         info = NS_REINTERPRET_CAST(nsXPTMethodInfo*,
00351                                    &mInterface->mDescriptor->
00352                                         method_descriptors[i]);
00353         if (PL_strcmp(methodName, info->GetName()) == 0) {
00354             *index = i + mInterface->mMethodBaseIndex;
00355             *result = info;
00356             return NS_OK;
00357         }
00358     }
00359     
00360     if(mInterface->mParent)
00361         return mInterface->mParent->GetMethodInfoForName(methodName, index, result);
00362     else
00363     {
00364         *index = 0;
00365         *result = 0;
00366         return NS_ERROR_INVALID_ARG;
00367     }
00368 }
00369 
00370 nsresult
00371 xptiInterfaceEntry::GetConstant(uint16 index, const nsXPTConstant** constant)
00372 {
00373     if(!EnsureResolved())
00374         return NS_ERROR_UNEXPECTED;
00375 
00376     if(index < mInterface->mConstantBaseIndex)
00377         return mInterface->mParent->GetConstant(index, constant);
00378 
00379     if(index >= mInterface->mConstantBaseIndex + 
00380                 mInterface->mDescriptor->num_constants)
00381     {
00382         NS_PRECONDITION(0, "bad param");
00383         *constant = NULL;
00384         return NS_ERROR_INVALID_ARG;
00385     }
00386 
00387     // else...
00388     *constant =
00389         NS_REINTERPRET_CAST(nsXPTConstant*,
00390                             &mInterface->mDescriptor->
00391                                 const_descriptors[index -
00392                                     mInterface->mConstantBaseIndex]);
00393     return NS_OK;
00394 }
00395 
00396 // this is a private helper
00397 
00398 nsresult 
00399 xptiInterfaceEntry::GetEntryForParam(PRUint16 methodIndex, 
00400                                      const nsXPTParamInfo * param,
00401                                      xptiInterfaceEntry** entry)
00402 {
00403     if(!EnsureResolved())
00404         return NS_ERROR_UNEXPECTED;
00405 
00406     if(methodIndex < mInterface->mMethodBaseIndex)
00407         return mInterface->mParent->GetEntryForParam(methodIndex, param, entry);
00408 
00409     if(methodIndex >= mInterface->mMethodBaseIndex + 
00410                       mInterface->mDescriptor->num_methods)
00411     {
00412         NS_ERROR("bad param");
00413         return NS_ERROR_INVALID_ARG;
00414     }
00415 
00416     const XPTTypeDescriptor *td = &param->type;
00417 
00418     while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
00419         td = &mInterface->mDescriptor->additional_types[td->type.additional_type];
00420     }
00421 
00422     if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
00423         NS_ERROR("not an interface");
00424         return NS_ERROR_INVALID_ARG;
00425     }
00426 
00427     xptiInterfaceEntry* theEntry = 
00428             mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)->
00429                 GetEntryAt(td->type.iface - 1);
00430     
00431     // This can happen if a declared interface is not available at runtime.
00432     if(!theEntry)
00433     {
00434         NS_WARNING("Declared InterfaceInfo not found");
00435         *entry = nsnull;
00436         return NS_ERROR_FAILURE;
00437     }
00438 
00439     *entry = theEntry;
00440     return NS_OK;
00441 }
00442 
00443 nsresult
00444 xptiInterfaceEntry::GetInfoForParam(uint16 methodIndex,
00445                                     const nsXPTParamInfo *param,
00446                                     nsIInterfaceInfo** info)
00447 {
00448     xptiInterfaceEntry* entry;
00449     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
00450     if(NS_FAILED(rv))
00451         return rv;
00452 
00453     xptiInterfaceInfo* theInfo;
00454     rv = entry->GetInterfaceInfo(&theInfo);    
00455     if(NS_FAILED(rv))
00456         return rv;
00457 
00458     *info = NS_STATIC_CAST(nsIInterfaceInfo*, theInfo);
00459     return NS_OK;
00460 }
00461 
00462 nsresult
00463 xptiInterfaceEntry::GetIIDForParam(uint16 methodIndex,
00464                                    const nsXPTParamInfo* param, nsIID** iid)
00465 {
00466     xptiInterfaceEntry* entry;
00467     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
00468     if(NS_FAILED(rv))
00469         return rv;
00470     return entry->GetIID(iid);
00471 }
00472 
00473 nsresult
00474 xptiInterfaceEntry::GetIIDForParamNoAlloc(PRUint16 methodIndex, 
00475                                           const nsXPTParamInfo * param, 
00476                                           nsIID *iid)
00477 {
00478     xptiInterfaceEntry* entry;
00479     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
00480     if(NS_FAILED(rv))
00481         return rv;
00482     *iid = entry->mIID;    
00483     return NS_OK;
00484 }
00485 
00486 // this is a private helper
00487 nsresult
00488 xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
00489                                   uint16 dimension,
00490                                   const XPTTypeDescriptor** type)
00491 {
00492     NS_ASSERTION(IsFullyResolved(), "bad state");
00493 
00494     const XPTTypeDescriptor *td = &param->type;
00495     const XPTTypeDescriptor *additional_types =
00496                 mInterface->mDescriptor->additional_types;
00497 
00498     for (uint16 i = 0; i < dimension; i++) {
00499         if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) {
00500             NS_ERROR("bad dimension");
00501             return NS_ERROR_INVALID_ARG;
00502         }
00503         td = &additional_types[td->type.additional_type];
00504     }
00505 
00506     *type = td;
00507     return NS_OK;
00508 }
00509 
00510 nsresult
00511 xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex,
00512                                     const nsXPTParamInfo* param,
00513                                     uint16 dimension,
00514                                     nsXPTType* type)
00515 {
00516     if(!EnsureResolved())
00517         return NS_ERROR_UNEXPECTED;
00518 
00519     if(methodIndex < mInterface->mMethodBaseIndex)
00520         return mInterface->mParent->
00521             GetTypeForParam(methodIndex, param, dimension, type);
00522 
00523     if(methodIndex >= mInterface->mMethodBaseIndex + 
00524                       mInterface->mDescriptor->num_methods)
00525     {
00526         NS_ERROR("bad index");
00527         return NS_ERROR_INVALID_ARG;
00528     }
00529 
00530     const XPTTypeDescriptor *td;
00531 
00532     if(dimension) {
00533         nsresult rv = GetTypeInArray(param, dimension, &td);
00534         if(NS_FAILED(rv))
00535             return rv;
00536     }
00537     else
00538         td = &param->type;
00539 
00540     *type = nsXPTType(td->prefix);
00541     return NS_OK;
00542 }
00543 
00544 nsresult
00545 xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16 methodIndex,
00546                                                const nsXPTParamInfo* param,
00547                                                uint16 dimension,
00548                                                uint8* argnum)
00549 {
00550     if(!EnsureResolved())
00551         return NS_ERROR_UNEXPECTED;
00552 
00553     if(methodIndex < mInterface->mMethodBaseIndex)
00554         return mInterface->mParent->
00555             GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum);
00556 
00557     if(methodIndex >= mInterface->mMethodBaseIndex + 
00558                       mInterface->mDescriptor->num_methods)
00559     {
00560         NS_ERROR("bad index");
00561         return NS_ERROR_INVALID_ARG;
00562     }
00563 
00564     const XPTTypeDescriptor *td;
00565 
00566     if(dimension) {
00567         nsresult rv = GetTypeInArray(param, dimension, &td);
00568         if(NS_FAILED(rv))
00569             return rv;
00570     }
00571     else
00572         td = &param->type;
00573 
00574     // verify that this is a type that has size_is
00575     switch (XPT_TDP_TAG(td->prefix)) {
00576       case TD_ARRAY:
00577       case TD_PSTRING_SIZE_IS:
00578       case TD_PWSTRING_SIZE_IS:
00579         break;
00580       default:
00581         NS_ERROR("not a size_is");
00582         return NS_ERROR_INVALID_ARG;
00583     }
00584 
00585     *argnum = td->argnum;
00586     return NS_OK;
00587 }
00588 
00589 nsresult
00590 xptiInterfaceEntry::GetLengthIsArgNumberForParam(uint16 methodIndex,
00591                                                  const nsXPTParamInfo* param,
00592                                                  uint16 dimension,
00593                                                  uint8* argnum)
00594 {
00595     if(!EnsureResolved())
00596         return NS_ERROR_UNEXPECTED;
00597 
00598     if(methodIndex < mInterface->mMethodBaseIndex)
00599         return mInterface->mParent->
00600             GetLengthIsArgNumberForParam(methodIndex, param, dimension, argnum);
00601 
00602     if(methodIndex >= mInterface->mMethodBaseIndex + 
00603                       mInterface->mDescriptor->num_methods)
00604     {
00605         NS_ERROR("bad index");
00606         return NS_ERROR_INVALID_ARG;
00607     }
00608 
00609     const XPTTypeDescriptor *td;
00610 
00611     if(dimension) {
00612         nsresult rv = GetTypeInArray(param, dimension, &td);
00613         if(NS_FAILED(rv)) {
00614             return rv;
00615         }
00616     }
00617     else
00618         td = &param->type;
00619 
00620     // verify that this is a type that has length_is
00621     switch (XPT_TDP_TAG(td->prefix)) {
00622       case TD_ARRAY:
00623       case TD_PSTRING_SIZE_IS:
00624       case TD_PWSTRING_SIZE_IS:
00625         break;
00626       default:
00627         NS_ERROR("not a length_is");
00628         return NS_ERROR_INVALID_ARG;
00629     }
00630 
00631     *argnum = td->argnum2;
00632     return NS_OK;
00633 }
00634 
00635 nsresult
00636 xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16 methodIndex,
00637                                                     const nsXPTParamInfo* param,
00638                                                     uint8* argnum)
00639 {
00640     if(!EnsureResolved())
00641         return NS_ERROR_UNEXPECTED;
00642 
00643     if(methodIndex < mInterface->mMethodBaseIndex)
00644         return mInterface->mParent->
00645             GetInterfaceIsArgNumberForParam(methodIndex, param, argnum);
00646 
00647     if(methodIndex >= mInterface->mMethodBaseIndex + 
00648                       mInterface->mDescriptor->num_methods)
00649     {
00650         NS_ERROR("bad index");
00651         return NS_ERROR_INVALID_ARG;
00652     }
00653 
00654     const XPTTypeDescriptor *td = &param->type;
00655 
00656     while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
00657         td = &mInterface->mDescriptor->
00658                                 additional_types[td->type.additional_type];
00659     }
00660 
00661     if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) {
00662         NS_ERROR("not an iid_is");
00663         return NS_ERROR_INVALID_ARG;
00664     }
00665 
00666     *argnum = td->argnum;
00667     return NS_OK;
00668 }
00669 
00670 /* PRBool isIID (in nsIIDPtr IID); */
00671 nsresult 
00672 xptiInterfaceEntry::IsIID(const nsIID * IID, PRBool *_retval)
00673 {
00674     // It is not necessary to Resolve because this info is read from manifest.
00675     *_retval = mIID.Equals(*IID);
00676     return NS_OK;
00677 }
00678 
00679 /* void getNameShared ([shared, retval] out string name); */
00680 nsresult 
00681 xptiInterfaceEntry::GetNameShared(const char **name)
00682 {
00683     // It is not necessary to Resolve because this info is read from manifest.
00684     *name = mName;
00685     return NS_OK;
00686 }
00687 
00688 /* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */
00689 nsresult 
00690 xptiInterfaceEntry::GetIIDShared(const nsIID * *iid)
00691 {
00692     // It is not necessary to Resolve because this info is read from manifest.
00693     *iid = &mIID;
00694     return NS_OK;
00695 }
00696 
00697 /* PRBool hasAncestor (in nsIIDPtr iid); */
00698 nsresult 
00699 xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval)
00700 {
00701     *_retval = PR_FALSE;
00702 
00703     for(xptiInterfaceEntry* current = this; 
00704         current;
00705         current = current->mInterface->mParent)
00706     {
00707         if(current->mIID.Equals(*iid))
00708         {
00709             *_retval = PR_TRUE;
00710             break;
00711         }
00712         if(!current->EnsureResolved())
00713             return NS_ERROR_UNEXPECTED;
00714     }
00715 
00716     return NS_OK;
00717 }
00718 
00719 /***************************************************/
00720 
00721 nsresult 
00722 xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info)
00723 {
00724     nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
00725     LOG_INFO_MONITOR_ENTRY;
00726 
00727 #ifdef SHOW_INFO_COUNT_STATS
00728     static int callCount = 0;
00729     if(!(++callCount%100))
00730         printf("iiii %d xptiInterfaceInfos currently alive\n", DEBUG_CurrentInfos);       
00731 #endif
00732 
00733     if(!mInfo)
00734     {
00735         mInfo = new xptiInterfaceInfo(this);
00736         if(!mInfo)
00737         {
00738             *info = nsnull;    
00739             return NS_ERROR_OUT_OF_MEMORY;
00740         }
00741     }
00742     
00743     NS_ADDREF(*info = mInfo);
00744     return NS_OK;    
00745 }
00746     
00747 void     
00748 xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
00749 {
00750     if(mInfo)
00751     {
00752         mInfo->Invalidate(); 
00753         mInfo = nsnull;
00754     }
00755 }
00756 
00757 /***************************************************************************/
00758 
00759 NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo)
00760 
00761 xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry)
00762     : mEntry(entry), mParent(nsnull)
00763 {
00764     LOG_INFO_CREATE(this);
00765 }
00766 
00767 xptiInterfaceInfo::~xptiInterfaceInfo() 
00768 {
00769     LOG_INFO_DESTROY(this);
00770     NS_IF_RELEASE(mParent); 
00771     NS_ASSERTION(!mEntry, "bad state in dtor");
00772 }
00773 
00774 nsrefcnt
00775 xptiInterfaceInfo::AddRef(void)
00776 {
00777     nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt);
00778     NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this));
00779     return cnt;
00780 }
00781 
00782 nsrefcnt
00783 xptiInterfaceInfo::Release(void)
00784 {
00785     xptiInterfaceEntry* entry = mEntry;
00786     nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
00787     NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
00788     if(!cnt)
00789     {
00790         nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
00791         LOG_INFO_MONITOR_ENTRY;
00792         
00793         // If GetInterfaceInfo added and *released* a reference before we 
00794         // acquired the monitor then 'this' might already be dead. In that
00795         // case we would not want to try to access any instance data. We
00796         // would want to bail immediately. If 'this' is already dead then the
00797         // entry will no longer have a pointer to 'this'. So, we can protect 
00798         // ourselves from danger without more aggressive locking.
00799         if(entry && !entry->InterfaceInfoEquals(this))
00800             return 0;
00801 
00802         // If GetInterfaceInfo added a reference before we acquired the monitor
00803         // then we want to bail out of here without destorying the object.
00804         if(mRefCnt)
00805             return 1;
00806         
00807         if(mEntry)
00808         {
00809             mEntry->LockedInterfaceInfoDeathNotification();
00810             mEntry = nsnull;
00811         }
00812 
00813         NS_DELETEXPCOM(this);
00814         return 0;    
00815     }
00816     return cnt;
00817 }
00818 
00819 /***************************************************************************/