00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00040 #include "TclXPCOMPrivate.h"
00041
00042
00043
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
00108
00109
00110
00111
00112
00113
00114
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
00199
00200
00201
00202
00203
00204
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
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
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
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
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 }