Main Page   Compound List   File List   Compound Members   File Members  

TclXPCOMClassInfo.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 #include "nsQuickSort.h"
00042 
00043 
00044 typedef struct ClassInfoList {
00045     ClassInfo            *cinfo;
00046     struct ClassInfoList *next;
00047 } ClassInfoList;
00048 
00049 
00050 typedef struct ClassInfoLookup {
00051     int              iidcount;
00052     nsIID            **iids;
00053     ClassInfo        *cinfo;
00054     struct ClassInfoLookup *next;
00055 } ClassInfoLookup;
00056 
00057 
00058 typedef struct InterfaceInfoList {
00059     InterfaceInfo *iinfo;
00060     struct InterfaceInfoList *next;
00061 } InterfaceInfoList;
00062 
00063 
00064 // XXX TODO: make classInfoList and classLookupTable threadsafe
00065 ClassInfoList   *classInfoList;
00066 ClassInfoLookup *classLookupTable;
00067 
00068 
00072 void
00073 TclXPCOM_InitClassInfo(void)
00074 {
00075     classInfoList    = NULL;
00076     classLookupTable = NULL;
00077 }
00078 
00079 
00085 InterfaceInfoList *
00086 NewInterfaceInfoList(
00087     nsIInterfaceInfo  *info, 
00088     InterfaceInfoList *next  
00089 )
00090 {
00091     NS_PRECONDITION(info, "null pointer");
00092 
00093     InterfaceInfoList *iilist;
00094     iilist = (InterfaceInfoList *)memmgr->Alloc(sizeof(InterfaceInfoList));
00095     iilist->iinfo = GetInterfaceInfo(info);
00096     iilist->next = next;
00097     return iilist;
00098 }
00099 
00100 
00104 void
00105 FreeInterfaceInfoList(
00106     InterfaceInfoList *iilist 
00107 )
00108 {
00109     InterfaceInfoList *cur_elem, *temp;
00110 
00111     NS_PRECONDITION(iilist, "null pointer");
00112 
00113     for (cur_elem = iilist; cur_elem;)
00114     {
00115         temp = cur_elem;
00116         cur_elem = cur_elem->next;
00117         memmgr->Free(temp);
00118     }
00119 }
00120 
00121 
00127 InterfaceInfoList *
00128 GetInterfaceInfoList(
00129     nsIInterfaceInfo  *info, 
00130     InterfaceInfoList *list  
00131 )
00132 {
00133     nsIInterfaceInfo *parent;
00134     InterfaceInfoList *iilist, *cur_elem;
00135 
00136     NS_PRECONDITION(info, "null pointer");
00137 
00138     for (cur_elem = list; cur_elem; cur_elem = cur_elem->next)
00139     {
00140         if (info == cur_elem->iinfo->info)
00141         {
00142             return NULL;
00143         }
00144     }
00145 
00146     info->GetParent(&parent);
00147     if (parent)
00148     {
00149         iilist = GetInterfaceInfoList(parent, list);
00150         NS_RELEASE(parent);
00151         return NewInterfaceInfoList(info, iilist);
00152     } else
00153     {
00154         return NewInterfaceInfoList(info, NULL);
00155     }
00156 }
00157 
00158 
00164 // given a list of iids,  returns an allocated array of addrefed interfaceinfos
00165 // without any ancestor redundancies
00166 ClassInfoSignature
00167 NewClassInfoSignature(
00168     int     iidcount, 
00169     nsIID **iids      
00170 )
00171 {
00172     int i, j;
00173     nsIInterfaceInfo **infos;
00174     ClassInfoSignature signature;
00175 
00176     NS_PRECONDITION((iidcount > 0), "iidcount must be greater than 0");
00177     NS_PRECONDITION(iids, "null pointer");
00178 
00179     infos = (nsIInterfaceInfo **)memmgr->Alloc(sizeof(nsIInterfaceInfo *) * iidcount);
00180     memset(infos, 0, sizeof(nsIInterfaceInfo *) * iidcount);
00181 
00182     signature.infocount = iidcount;
00183 
00184     for (i = 0; i < iidcount; i++)
00185     {
00186         manager->GetInfoForIID(iids[i], &infos[i]);
00187         if (!infos[i])
00188         {
00189             (signature.infocount)--;
00190         }
00191     }
00192 
00193     for (i = 0; i < iidcount; i++)
00194     {
00195         if (!infos[i])
00196         {
00197             continue;
00198         }
00199 
00200         for (j = 0; j < iidcount; j++)
00201         {
00202             if (infos[j] && (i != j) && isInInterface(infos[i], iids[j]))
00203             {
00204                 NS_RELEASE(infos[j]);
00205                 infos[j] = NULL;
00206                 (signature.infocount)--;
00207             }
00208         }
00209     }
00210 
00211     signature.infolist = (nsIInterfaceInfo **)memmgr->Alloc(sizeof(nsIInterfaceInfo *) * signature.infocount);
00212 
00213     j = 0;
00214 
00215     for (i = 0; i < iidcount; i++)
00216     {
00217         if (infos[i])
00218         {
00219             signature.infolist[j] = infos[i];
00220             j++;
00221         }
00222     }
00223 
00224     memmgr->Free(infos);
00225 
00226     return signature;
00227 }
00228 
00229 
00233 void
00234 FreeClassInfoSignature(
00235     ClassInfoSignature signature 
00236 )
00237 {
00238     int i;
00239 
00240     NS_PRECONDITION((signature.infocount > 0), "infocount must be greater than 0");
00241     NS_PRECONDITION(signature.infolist, "null pointer");
00242 
00243     for (i = 0; i < signature.infocount; i++)
00244     {
00245         NS_RELEASE(signature.infolist[i]);
00246     }
00247 
00248     if (signature.infolist)
00249     {
00250         memmgr->Free(signature.infolist);
00251     }
00252 }
00253 
00254 
00260 InterfaceInfoList *
00261 ExpandClassInfoSignature(
00262     ClassInfoSignature signature 
00263 )
00264 {
00265     int i;
00266     InterfaceInfoList *iilist, *cur_elem, *temp;
00267 
00268     NS_PRECONDITION((signature.infocount > 0), "infocount must be greater than 0");
00269     NS_PRECONDITION(signature.infolist, "null pointer");
00270 
00271     iilist = NULL;
00272     for (i = 0; i < signature.infocount; i++)
00273     {
00274         temp = GetInterfaceInfoList(signature.infolist[i], iilist);
00275 
00276         cur_elem = temp;
00277         while (cur_elem->next)
00278         {
00279             cur_elem = cur_elem->next;
00280         }
00281 
00282         cur_elem->next = iilist;
00283         iilist = temp;
00284     }
00285 
00286     return iilist;
00287 }
00288 
00289 
00295 int
00296 ClassInfoSignaturesEqual(
00297     ClassInfoSignature signaturea,
00298     ClassInfoSignature signatureb 
00299 )
00300 {
00301     NS_PRECONDITION((signaturea.infocount > 0), "infocount must be greater than 0");
00302     NS_PRECONDITION(signaturea.infolist, "null pointer");
00303     NS_PRECONDITION((signatureb.infocount > 0), "infocount must be greater than 0");
00304     NS_PRECONDITION(signatureb.infolist, "null pointer");
00305 
00306     if (signaturea.infocount == signatureb.infocount)
00307     {
00308         if (!memcmp((void *)signaturea.infolist,
00309                     (void *)signatureb.infolist,
00310                     sizeof(nsIInterfaceInfo *) * signaturea.infocount))
00311         {
00312             return 1;
00313         }
00314     }
00315     return 0;
00316 }
00317 
00318 
00322 void
00323 MarkDuplicateIdentifiersInArray(
00324     int                  idcount,
00325     ClassIdentifierInfo *idlist  
00326 )
00327 {
00328     int i, j;
00329 
00330     NS_PRECONDITION((idcount >= 0), "idcount must be positive");
00331     NS_PRECONDITION(!((idcount > 0) && !idlist), "null pointer");
00332 
00333     for (i = 0; i < idcount; i++)
00334     {
00335         if (idlist[i].qualified)
00336         {
00337             continue;
00338         }
00339 
00340         for (j = i + 1; j < idcount; j++)
00341         {
00342             if ((idlist[i].info == idlist[j].info) || idlist[j].qualified)
00343             {
00344                 continue;
00345             }
00346 
00347             if (!strcmp(idlist[i].idinfo.name, idlist[j].idinfo.name))
00348             {
00349                 idlist[j].qualified = 1;
00350                 idlist[i].qualified = 1;
00351             }
00352         }
00353     }
00354 }
00355 
00356 
00360 void
00361 MarkDuplicateIdentifiersBetweenArrays(
00362     int                  idcounta,
00363     ClassIdentifierInfo *idlista, 
00364     int                  idcountb,
00365     ClassIdentifierInfo *idlistb  
00366 )
00367 {
00368     int i, j;
00369 
00370     NS_PRECONDITION((idcounta >= 0), "idcounta must be positive");
00371     NS_PRECONDITION(!((idcounta > 0) && !idlista), "null pointer");
00372     NS_PRECONDITION((idcountb >= 0), "idcountb must be positive");
00373     NS_PRECONDITION(!((idcountb > 0) && !idlistb), "null pointer");
00374 
00375     for (i = 0; i < idcounta; i++)
00376     {
00377         for (j = 0; j < idcountb; j++)
00378         {
00379             if ((idlista[i].info == idlistb[j].info) || (idlista[i].qualified && idlistb[j].qualified))
00380             {
00381                 continue;
00382             }
00383 
00384             if (!strcmp(idlista[i].idinfo.name, idlistb[j].idinfo.name))
00385             {
00386                 idlista[i].qualified = 1;
00387                 idlistb[j].qualified = 1;
00388             }
00389         }
00390     }
00391 }
00392 
00393 
00398 void
00399 QualifyDuplicateIdentifiers(
00400     int                  idcount,
00401     ClassIdentifierInfo *idlist  
00402 )
00403 {
00404     int i;
00405     Tcl_Obj *identifierobj;
00406     char *identifier;
00407 
00408     NS_PRECONDITION((idcount >= 0), "idcount must be positive");
00409     NS_PRECONDITION(!((idcount > 0) && !idlist), "null pointer");
00410 
00411     for (i = 0; i < idcount; i++)
00412     {
00413         if (idlist[i].qualified)
00414         {
00415             identifierobj = TclXPCOM_NewIdentifierObj(idlist[i].info, idlist[i].idinfo.name);
00416             identifier = Tcl_GetString(identifierobj);
00417             idlist[i].idinfo.name = (char *)CloneMemory(identifier, sizeof(char) * (strlen(identifier) + 1));
00418             Tcl_DecrRefCount(identifierobj);
00419         }
00420     }
00421 }
00422 
00423 
00428 ClassIdentifierInfo *
00429 AllocateClassIdentifierInfoArray(
00430     int idcount 
00431 )
00432 {
00433     ClassIdentifierInfo *cidinfo;
00434 
00435     NS_PRECONDITION((idcount >= 0), "idcount must be positive");
00436 
00437     if (idcount)
00438     {
00439         cidinfo = (ClassIdentifierInfo *)memmgr->Alloc(sizeof(ClassIdentifierInfo) * idcount + sizeof(char *));
00440         memset(cidinfo, 0, sizeof(ClassIdentifierInfo) * idcount + sizeof(char *));
00441     } else
00442     {
00443         cidinfo = NULL;
00444     }
00445 
00446     return cidinfo;
00447 }
00448 
00449 
00455 ClassInfo *
00456 NewClassInfo(
00457     ClassInfoSignature signature 
00458 )
00459 {
00460     PRUint16 i, methodcount, attributecount;
00461 
00462     ClassInfo *cinfo;
00463     ClassIdentifierInfo *methods, *attributes;
00464     InterfaceInfoList *iilist, *cur_elem;
00465 
00466     NS_PRECONDITION((signature.infocount > 0), "infocount must be greater than 0");
00467     NS_PRECONDITION(signature.infolist, "null pointer");
00468 
00469     cinfo = (ClassInfo *)memmgr->Alloc(sizeof(ClassInfo));
00470 
00471     iilist = ExpandClassInfoSignature(signature);
00472 
00473     // count the number of methods and attributes
00474     attributecount = 0;
00475     methodcount    = 0;
00476 
00477     for (cur_elem = iilist; cur_elem; cur_elem = cur_elem->next)
00478     {
00479         attributecount += cur_elem->iinfo->attributecount - cur_elem->iinfo->baseattributeindex;
00480         methodcount    += cur_elem->iinfo->methodcount    - cur_elem->iinfo->basemethodindex;
00481     }
00482 
00483     // allocate memory for the attribute and method infos
00484     attributes = AllocateClassIdentifierInfoArray(attributecount);
00485     methods    = AllocateClassIdentifierInfoArray(methodcount);
00486 
00487     // fill attribute and method info
00488     attributecount = 0;
00489     methodcount    = 0;
00490 
00491     for (cur_elem = iilist; cur_elem; cur_elem = cur_elem->next)
00492     {
00493         for (i = cur_elem->iinfo->baseattributeindex; i < cur_elem->iinfo->attributecount; i++)
00494         {
00495             attributes[attributecount].info   = cur_elem->iinfo->info;
00496             attributes[attributecount].idinfo = cur_elem->iinfo->attributes[i];
00497             attributecount++;
00498         }
00499 
00500         for (i = cur_elem->iinfo->basemethodindex; i < cur_elem->iinfo->methodcount; i++)
00501         {
00502             methods[methodcount].info   = cur_elem->iinfo->info;
00503             methods[methodcount].idinfo = cur_elem->iinfo->methods[i];
00504             methodcount++;
00505         }
00506     }
00507 
00508     MarkDuplicateIdentifiersInArray(attributecount, attributes);
00509     MarkDuplicateIdentifiersInArray(methodcount, methods);
00510     MarkDuplicateIdentifiersBetweenArrays(attributecount, attributes, methodcount, methods);
00511 
00512     QualifyDuplicateIdentifiers(attributecount, attributes);
00513     QualifyDuplicateIdentifiers(methodcount, methods);
00514 
00515     FreeInterfaceInfoList(iilist);
00516 
00517     // fill in structure
00518     cinfo->signature      = signature;
00519     cinfo->methodcount    = methodcount;
00520     cinfo->attributecount = attributecount;
00521     cinfo->methods        = methods;
00522     cinfo->attributes     = attributes;
00523 
00524     return cinfo;
00525 }
00526 
00527 
00531 void
00532 FreeClassInfo(
00533     ClassInfo *cinfo 
00534 )
00535 {
00536     PRUint16 i;
00537 
00538     NS_PRECONDITION(cinfo, "null pointer");
00539 
00540     FreeClassInfoSignature(cinfo->signature);
00541 
00542     for (i = 0; i < cinfo->methodcount; i++)
00543     {
00544         if (cinfo->methods[i].qualified)
00545         {
00546             memmgr->Free(cinfo->methods[i].idinfo.name);
00547         }
00548     }
00549 
00550     for (i = 0; i < cinfo->attributecount; i++)
00551     {
00552         if (cinfo->attributes[i].qualified)
00553         {
00554             memmgr->Free(cinfo->attributes[i].idinfo.name);
00555         }
00556     }
00557 
00558     if (cinfo->methods)
00559     {
00560         memmgr->Free(cinfo->methods);
00561     }
00562 
00563     if (cinfo->attributes)
00564     {
00565         memmgr->Free(cinfo->attributes);
00566     }
00567 
00568     memmgr->Free(cinfo);
00569 }
00570 
00571 
00577 ClassInfo *
00578 FindMatchingClassInfo(
00579     ClassInfoSignature signature 
00580 )
00581 {
00582     ClassInfoList *cur_elem;
00583 
00584     NS_PRECONDITION((signature.infocount > 0), "infocount must be greater than 0");
00585     NS_PRECONDITION(signature.infolist, "null pointer");
00586 
00587     for (cur_elem = classInfoList; cur_elem; cur_elem = cur_elem->next)
00588     {
00589         if (ClassInfoSignaturesEqual(cur_elem->cinfo->signature, signature))
00590         {
00591             return cur_elem->cinfo;
00592         }
00593     }
00594     return NULL;
00595 }
00596 
00597 
00603 int
00604 CompareNsIDs(
00605     const void *nsidPtra, 
00606     const void *nsidPtrb, 
00607     void       *userdata  
00608 )
00609 {
00610     return memcmp(*(void **)nsidPtra,
00611                   *(void **)nsidPtrb,
00612                   sizeof(nsID));
00613 }
00614 
00615 
00621 ClassInfo *
00622 LookupClassInfo(
00623     int     iidcount, 
00624     nsIID **iids      
00625 )
00626 {
00627     int i, match;
00628     ClassInfoLookup *clist;
00629 
00630     NS_PRECONDITION((iidcount > 0), "iidcount must be greater than 0");
00631     NS_PRECONDITION(iids, "null pointer");
00632 
00633     for (clist = classLookupTable; clist; clist = clist->next)
00634     {
00635         if (clist->iidcount == iidcount)
00636         {
00637             match = 1;
00638 
00639             for (i = 0; i < iidcount; i++)
00640             {
00641                 if (!clist->iids[i]->Equals(*iids[i]))
00642                 {
00643                     match = 0;
00644                     break;
00645                 }
00646             }
00647 
00648             if (match)
00649             {
00650                 return clist->cinfo;
00651             }
00652         }
00653     }
00654 
00655     return NULL;
00656 }
00657 
00658 
00664 ClassInfo *
00665 TclXPCOM_GetClassInfo(
00666     int     iidcount, 
00667     nsIID **iids      
00668 )
00669 {
00670     int i;
00671     ClassInfoLookup *cinfolookup;
00672     ClassInfoList *cinfolist;
00673     ClassInfo *cinfo;
00674     nsIID **iidlist;
00675     ClassInfoSignature signature;
00676 
00677     NS_PRECONDITION((iidcount > 0), "iidcount must be greater than 0");
00678     NS_PRECONDITION(iids, "null pointer");
00679 
00680     // sort the iids
00681     NS_QuickSort(iids, iidcount, sizeof(nsIID *), CompareNsIDs, NULL);
00682 
00683     cinfo = LookupClassInfo(iidcount, iids);
00684 
00685     if (cinfo)
00686     {
00687         return cinfo;
00688     }
00689 
00690     signature = NewClassInfoSignature(iidcount, iids);
00691     cinfo = FindMatchingClassInfo(signature);
00692 
00693     if (!cinfo)
00694     {
00695         cinfo = NewClassInfo(signature);
00696         cinfolist = (ClassInfoList *)memmgr->Alloc(sizeof(ClassInfoList));
00697         cinfolist->cinfo = cinfo;
00698         cinfolist->next  = classInfoList;
00699         classInfoList    = cinfolist;
00700     } else
00701     {
00702         FreeClassInfoSignature(signature);
00703     }
00704 
00705     cinfolookup = (ClassInfoLookup *)memmgr->Alloc(sizeof(ClassInfoLookup));
00706     cinfolookup->cinfo    = cinfo;
00707     cinfolookup->iidcount = iidcount;
00708 
00709     iidlist = (nsIID **)memmgr->Alloc(sizeof(nsIID *) * iidcount);
00710     for (i = 0; i < iidcount; i++)
00711     {
00712         iidlist[i] = (nsIID *)CloneMemory(iids[i], sizeof(nsIID));
00713     }
00714 
00715     cinfolookup->iids  = iidlist;
00716     cinfolookup->next  = classLookupTable;
00717     classLookupTable   = cinfolookup;
00718 
00719     return cinfo;
00720 }
00721 
00722 
00728 int
00729 TclXPCOM_GetIdentifierInfoFromClass(
00730     Tcl_Interp        *interp,       
00731     ClassInfo         *cinfo,        
00732     Tcl_Obj           *identifier,   
00733     int                type,         
00734     nsIInterfaceInfo **interfaceinfo,
00735     IdentifierInfo   **idinfo        
00736 )
00737 {
00738     int rv;
00739     int index;
00740     int count;
00741     char *name;
00742     ClassIdentifierInfo *cidinfos;
00743 
00744     NS_PRECONDITION(interp, "null pointer");
00745     NS_PRECONDITION(cinfo, "null pointer");
00746     NS_PRECONDITION(identifier, "null pointer");
00747     NS_PRECONDITION(((type == INTERFACEINFO_METHOD) || (type == INTERFACEINFO_SETTER) || (type == INTERFACEINFO_GETTER)), "invalid identifier type code");
00748     NS_PRECONDITION(interfaceinfo, "null pointer");
00749     NS_PRECONDITION(idinfo, "null pointer");
00750 
00751     switch (type)
00752     {
00753         case INTERFACEINFO_METHOD:
00754             count    = cinfo->methodcount;
00755             cidinfos = cinfo->methods;
00756             name     = "method";
00757             break;
00758 
00759         case INTERFACEINFO_SETTER:
00760         case INTERFACEINFO_GETTER:
00761             count    = cinfo->attributecount;
00762             cidinfos = cinfo->attributes;
00763             name     = "attribute";
00764             break;
00765     }
00766 
00767     Tcl_ResetResult(interp);
00768     if (count)
00769     {
00770         rv = Tcl_GetIndexFromObjStruct(interp, identifier, (char **)&cidinfos[0].idinfo.name, sizeof(ClassIdentifierInfo), name, 0, &index);
00771         if (rv != TCL_OK)
00772         {
00773             return rv;
00774         }
00775 
00776     } else
00777     {
00778         Tcl_AppendResult(interp, "no ", name, "s in class", NULL);
00779         return TCL_ERROR;
00780     }
00781 
00782     *idinfo         = &cidinfos[index].idinfo;
00783     *interfaceinfo  =  cidinfos[index].info;
00784     return TCL_OK;
00785 }
00786 

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