Main Page   Compound List   File List   Compound Members   File Members  

TclXPCOMInterfaceRef.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * The contents of this file are subject to the Mozilla Public License Version
00004  * 1.1 (the "License"); you may not use this file except in compliance with
00005  * the License. You may obtain a copy of the License at
00006  * http://www.mozilla.org/MPL/
00007  *
00008  * Software distributed under the License is distributed on an "AS IS" basis,
00009  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00010  * for the specific language governing rights and limitations under the
00011  * License.
00012  *
00013  * The Original Code is TclXPCOM.
00014  * 
00015  * The Initial Developer of the Original Code is Mark Follett.
00016  * Portions created by Mark Follett are Copyright (C) 2001-2002
00017  * Mark Follett.  All Rights Reserved.
00018  * 
00019  * Contributor(s):
00020  *     Mark Follett <mef123@myrealbox.com> (Original Author)
00021  *
00022  * Alternatively, the contents of this file may be used under the terms of
00023  * either the GNU General Public License Version 2 or later (the "GPL"), or
00024  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00025  * in which case the provisions of the GPL or the LGPL are applicable instead
00026  * of those above. If you wish to allow use of your version of this file only
00027  * under the terms of either the GPL or the LGPL, and not to allow others to
00028  * use your version of this file under the terms of the MPL, indicate your
00029  * decision by deleting the provisions above and replace them with the notice
00030  * and other provisions required by the GPL or the LGPL. If you do not delete
00031  * the provisions above, a recipient may use your version of this file under
00032  * the terms of any one of the MPL, the GPL or the LGPL.
00033  */
00034 
00040 #include "TclXPCOMPrivate.h"
00041 
00042 
00043 // XXX TODO: make irefhash threadsafe
00044 Tcl_HashTable irefhash;
00045 
00046 
00052 InterfaceRef *
00053 NewInterfaceRef(void)
00054 {
00055     InterfaceRef *iref;
00056 
00057     iref = (InterfaceRef *)memmgr->Alloc(sizeof(InterfaceRef));
00058 
00059     Tcl_InitHashTable(&iref->refhash, TCL_ONE_WORD_KEYS);
00060 
00061     iref->refcount    = 0;
00062     iref->cinforef    = NULL;
00063     iref->cinfo       = NULL;
00064     iref->cisupported = 1;
00065 
00066     return iref;
00067 }
00068 
00069 
00077 Tcl_HashEntry *
00078 AddISupportsToInterfaceRef(
00079     InterfaceRef     *iref,         
00080     nsISupports      *isupports,    
00081     nsIInterfaceInfo *interfaceinfo 
00082 )
00083 {
00084     int newentry;
00085     Tcl_HashEntry *entry;
00086 
00087     NS_PRECONDITION(iref, "null pointer");
00088     NS_PRECONDITION(isupports, "null pointer");
00089     NS_PRECONDITION(interfaceinfo, "null pointer");
00090 
00091     entry = Tcl_CreateHashEntry(&irefhash, (char *)isupports, &newentry);
00092     if (newentry)
00093     {
00094         Tcl_SetHashValue(entry, iref);
00095         NS_ADDREF(isupports);
00096     }
00097 
00098     entry = Tcl_CreateHashEntry(&iref->refhash, (char *)interfaceinfo, &newentry);
00099     if (newentry)
00100     {
00101         Tcl_SetHashValue(entry, isupports);
00102         NS_ADDREF(interfaceinfo);
00103     }
00104 
00105     return entry;
00106 
00107 //        char str[128];
00108 //        char str1[128];
00109 //        const char *name;
00110 //        interfaceinfo->GetNameShared(&name);
00111 //        sprintf(str, "xpcom::inscope %s::%p", name, isupports);
00112 //        sprintf(str1, "Adding to iref %p: %s", iref, str);
00113 //        NS_WARNING(str1);
00114 //        printf("Adding to iref %p: %s\n", iref, str);
00115 
00116 }
00117 
00118 
00124 void
00125 MergeInterfaceRefs(
00126     InterfaceRef *irefa, 
00127     InterfaceRef *irefb  
00128 )
00129 {
00130     int newentry;
00131     Tcl_HashEntry  *entrya, *entryb, *refentry;
00132     Tcl_HashSearch search;
00133     nsIInterfaceInfo *interfaceinfo;
00134     nsISupports      *isupports;
00135 
00136     NS_PRECONDITION(irefa, "null pointer");
00137     NS_PRECONDITION(irefb, "null pointer");
00138 
00139     NS_ASSERTION(!(irefa == irefb), "attempting to merge an InterfaceRef with itself");
00140 
00141     for (entryb = Tcl_FirstHashEntry(&irefb->refhash, &search); entryb; entryb = Tcl_NextHashEntry(&search))
00142     {
00143         interfaceinfo = (nsIInterfaceInfo *)Tcl_GetHashKey(&irefb->refhash, entryb);
00144         isupports     = (nsISupports      *)Tcl_GetHashValue(entryb);
00145 
00146         entrya = Tcl_CreateHashEntry(&irefa->refhash, (char *)interfaceinfo, &newentry);
00147 
00148         NS_ASSERTION(newentry, "interfaceinfo entry must not already exist in this iref");
00149 
00150         Tcl_SetHashValue(entrya, isupports);
00151 
00152         refentry = Tcl_FindHashEntry(&irefhash, (char *)isupports);
00153         Tcl_SetHashValue(refentry, irefa);
00154     }
00155 
00156     Tcl_DeleteHashTable(&irefb->refhash);
00157 
00158     irefa->refcount += irefb->refcount;
00159     irefa->cisupported &= irefb->cisupported;
00160 
00161     if (!irefa->cinforef && irefb->cinforef)
00162     {
00163         irefa->cinforef = irefb->cinforef;
00164     } else if (irefb->cinforef)
00165     {
00166         NS_RELEASE(irefb->cinforef);
00167     }
00168 
00169     if (irefb->cinfo)
00170     {
00171         irefa->cinfo = irefb->cinfo;
00172     }
00173 
00174     memmgr->Free(irefb);
00175 }
00176 
00177 
00181 void
00182 FreeInterfaceRef(
00183     InterfaceRef *iref 
00184 )
00185 {
00186     Tcl_HashEntry    *entry, *deletedentry;
00187     Tcl_HashSearch    search;
00188     nsIInterfaceInfo *interfaceinfo;
00189     nsISupports      *isupports;
00190 
00191     NS_PRECONDITION(iref, "null pointer");
00192 
00193     for (entry = Tcl_FirstHashEntry(&iref->refhash, &search); entry; entry = Tcl_NextHashEntry(&search))
00194     {
00195         interfaceinfo = (nsIInterfaceInfo *)Tcl_GetHashKey(&iref->refhash, entry);
00196         isupports     = (nsISupports      *)Tcl_GetHashValue(entry);
00197 
00198 //        char str[128];
00199 //        char str1[128];
00200 //        const char *name;
00201 //        interfaceinfo->GetNameShared(&name);
00202 //        sprintf(str, "xpcom::inscope %s::%p", name, isupports);
00203 //        sprintf(str1, "Removing from iref %p: %s", iref, str);
00204 //        NS_WARNING(str1);
00205 
00206         deletedentry = Tcl_FindHashEntry(&irefhash, (char *)isupports);
00207 
00208         if (deletedentry)
00209         {
00210             NS_ASSERTION((Tcl_GetHashValue(deletedentry) == iref), "deleted entry doesn't point to this iref");
00211             Tcl_DeleteHashEntry(deletedentry);
00212             NS_RELEASE(isupports);
00213         }
00214 
00215         NS_RELEASE(interfaceinfo);
00216     }
00217 
00218     Tcl_DeleteHashTable(&iref->refhash);
00219 
00220     if (iref->cinforef)
00221     {
00222         NS_RELEASE(iref->cinforef);
00223     }
00224 
00225     memmgr->Free(iref);
00226 }
00227 
00228 
00237 int
00238 AddRefInterface(
00239     nsISupports      *isupports,    
00240     nsIInterfaceInfo *interfaceinfo,
00241     Tcl_HashEntry   **entryout      
00242 )
00243 {
00244     InterfaceRef *iref;
00245     Tcl_HashEntry *entry;
00246 
00247     NS_PRECONDITION(isupports, "null pointer");
00248     NS_PRECONDITION(interfaceinfo, "null pointer");
00249     // no precondition on entryout
00250 
00251     iref = GetInterfaceRef(isupports);
00252 
00253     if (!iref)
00254     {
00255         iref = NewInterfaceRef();
00256     }
00257 
00258     entry = AddISupportsToInterfaceRef(iref, isupports, interfaceinfo);
00259     if (entryout)
00260     {
00261         *entryout = entry;
00262     }
00263 
00264     iref->refcount++;
00265 //  printf("(Addrefed)Refcount: %d\n", iref->refcount);
00266     return iref->refcount;
00267 }
00268 
00269 
00276 int
00277 ReleaseInterface(
00278     nsISupports *isupports 
00279 )
00280 {
00281     InterfaceRef *iref;
00282 
00283     NS_PRECONDITION(isupports, "null pointer");
00284 
00285     iref = GetInterfaceRef(isupports);
00286 
00287     NS_ASSERTION(iref, "attempting to release an unknown isupports");
00288 
00289     iref->refcount--;
00290 //  printf("(Released)Refcount: %d\n", iref->refcount);
00291     if (iref->refcount <= 0)
00292     {
00293         FreeInterfaceRef(iref);
00294     }
00295     return iref->refcount;
00296 }
00297 
00298 
00306 InterfaceRef *
00307 GetInterfaceRef(
00308     nsISupports *isupports 
00309 )
00310 {
00311     Tcl_HashEntry *entry;
00312 
00313     NS_PRECONDITION(isupports, "null pointer");
00314 
00315     entry = Tcl_FindHashEntry(&irefhash, (char *)isupports);
00316 
00317     if (entry)
00318     {
00319         return (InterfaceRef *)Tcl_GetHashValue(entry);
00320     } else
00321     {
00322         return NULL;
00323     }
00324 }
00325 
00326 
00336 int
00337 QueryInterfaceIRef(
00338     Tcl_Interp        *interp,   
00339     InterfaceRef      *iref,     
00340     nsIInterfaceInfo  *queryinfo,
00341     nsISupports      **result    
00342 )
00343 {
00344     nsresult res;
00345     Tcl_HashEntry *entry, *firstentry;
00346     Tcl_HashSearch search;
00347     const nsIID *iid;
00348     nsISupports *isupports, *firstisupports;
00349     InterfaceRef *irefb;
00350 
00351     // no precondition on interp
00352     NS_PRECONDITION(iref, "null pointer");
00353     NS_PRECONDITION(queryinfo, "null pointer");
00354     NS_PRECONDITION(result, "null pointer");
00355 
00356     entry = Tcl_FindHashEntry(&iref->refhash, (char *)queryinfo);
00357     if (!entry)
00358     {
00359         if ((queryinfo == nsiclassinfo_info) && iref->cinforef)
00360         {
00361             *result = iref->cinforef;
00362             return TCL_OK;
00363         }
00364 
00365         queryinfo->GetIIDShared(&iid);
00366 
00367         firstentry = Tcl_FirstHashEntry(&iref->refhash, &search);
00368         firstisupports = (nsISupports *)Tcl_GetHashValue(firstentry);
00369 
00370         res = firstisupports->QueryInterface(*iid, (void **)&isupports);
00371 
00372         if (NS_FAILED(res))
00373         {
00374             if (interp)
00375             {
00376                 TclXPCOM_SetError(interp, res);
00377             }
00378             return TCL_ERROR;
00379         }
00380 
00381         if (queryinfo == nsiclassinfo_info)
00382         {
00383             iref->cinforef = (nsIClassInfo *)isupports;
00384             NS_ADDREF(iref->cinforef);
00385         } else
00386         {
00387             irefb = GetInterfaceRef(isupports);
00388 
00389             if (irefb && (iref != irefb))
00390             {
00391                 MergeInterfaceRefs(iref, irefb);
00392             } else
00393             {
00394                 AddISupportsToInterfaceRef(iref, isupports, queryinfo);
00395             }
00396         }
00397 
00398         *result = isupports;
00399         NS_RELEASE(isupports);
00400 
00401     } else
00402     {
00403         *result = (nsISupports *)Tcl_GetHashValue(entry);
00404     }
00405 
00406     return TCL_OK;
00407 }
00408 
00409 
00417 ClassInfo *
00418 GetClassInfoFromIRef(
00419     InterfaceRef *iref 
00420 )
00421 {
00422     int rv;
00423     nsresult res;
00424     nsIClassInfo *cinforef;
00425     PRUint32 iidcount, i;
00426     nsIID **iids;
00427 
00428     NS_PRECONDITION(iref, "null pointer");
00429 
00430     if (iref->cinfo)
00431     {
00432         return iref->cinfo;
00433     }
00434 
00435     if (!iref->cisupported)
00436     {
00437         return NULL;
00438     }
00439     
00440     rv = QueryInterfaceIRef(NULL, iref, nsiclassinfo_info, (nsISupports **)&cinforef);
00441 
00442     if (rv != TCL_OK)
00443     {
00444         iref->cisupported = 0;
00445         return NULL;
00446     }
00447 
00448     res = cinforef->GetInterfaces(&iidcount, &iids);
00449 
00450     if (NS_FAILED(res) || iidcount == 0)
00451     {
00452         iref->cisupported = 0;
00453         return NULL;
00454     }
00455 
00456     iref->cinfo = TclXPCOM_GetClassInfo(iidcount, iids);
00457 
00458     for (i = 0; i < iidcount; i++)
00459     {
00460         memmgr->Free(iids[i]);
00461     }
00462 
00463     memmgr->Free(iids);
00464 
00465     return iref->cinfo;
00466 }
00467 
00468 
00476 int
00477 GetMethodFromIRef(
00478     Tcl_Interp        *interp,       
00479     nsISupports       *isupports,    
00480     nsIInterfaceInfo  *interfaceinfo,
00481     Tcl_Obj           *identifier,   
00482     int                type,         
00483     nsIInterfaceInfo **infoout,      
00484     PRUint16          *methodindex   
00485 )
00486 {
00487     int rv;
00488     char *name;
00489     Tcl_Obj *nameobj;
00490     ClassInfo *cinfo;
00491     IdentifierInfo *idinfo;
00492 
00493     NS_PRECONDITION(interp, "null pointer");
00494     NS_PRECONDITION(isupports, "null pointer");
00495     NS_PRECONDITION(interfaceinfo, "null pointer");
00496     NS_PRECONDITION(identifier, "null pointer");
00497     NS_PRECONDITION(((type == INTERFACEINFO_METHOD) || (type == INTERFACEINFO_SETTER) || (type == INTERFACEINFO_GETTER)), "invalid identifier type code");
00498     NS_PRECONDITION(infoout, "null pointer");
00499     NS_PRECONDITION(methodindex, "null pointer");
00500 
00501     rv = TclXPCOM_GetIdentifierFromObj(interp, identifier, infoout, &name);
00502     if (rv != TCL_OK)
00503     {
00504         return rv;
00505     }
00506 
00507     if (*infoout)
00508     {
00509         nameobj = Tcl_NewStringObj(name, -1);
00510         rv = TclXPCOM_GetIdentifierInfoFromInterface(interp, *infoout, nameobj, type, &idinfo);
00511         Tcl_DecrRefCount(nameobj);
00512 
00513     } else
00514     {
00515         rv = TclXPCOM_GetIdentifierInfoFromInterface(interp, interfaceinfo, identifier, type, &idinfo);
00516         if (rv == TCL_OK)
00517         {
00518             *infoout = interfaceinfo;
00519         } else
00520         {
00521             if (interfaceinfo != nsiclassinfo_info)
00522             {
00523                 NS_ASSERTION((GetInterfaceRef(isupports)), "isupports entry doesn't exist in irefhash");
00524 
00525                 cinfo = GetClassInfoFromIRef(GetInterfaceRef(isupports));
00526                 if (cinfo)
00527                 {
00528                     rv = TclXPCOM_GetIdentifierInfoFromClass(interp, cinfo, identifier, type, infoout, &idinfo);
00529                 }
00530             }
00531         }
00532     }
00533 
00534     if (rv == TCL_OK)
00535     {
00536         rv = TclXPCOM_GetMethodIndex(interp, idinfo, type, methodindex);
00537     }
00538 
00539     return rv;
00540 }
00541 
00542 
00546 void
00547 TclXPCOM_InitInterfaceRef(void)
00548 {
00549     Tcl_InitHashTable(&irefhash, TCL_ONE_WORD_KEYS);
00550 }

Generated on Fri Jun 14 23:25:51 2002 for TclXPCOM by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002