From 2c5a38de3eb7ad84ccf03d84a1c3ca4f7255ca6b Mon Sep 17 00:00:00 2001 From: "mccabe%netscape.com" Date: Wed, 10 Mar 1999 04:26:15 +0000 Subject: [PATCH] Not yet part of Seamonkey. Progress on the nsInterfaceInfoManager typelib loader for xpconnect. Now has complete (I think) functionality, though the implementation is still probably rusty. I punted on defining a directory for .xpt files at this point; the implementation looks at the value of the XPTDIR environment variable for this value. Note that the nsXPTParaminfo interface (public/xpt_cpp) has changed (possibly temporarily) to take an 'entry' parameter. git-svn-id: svn://10.0.0.236/trunk@23485 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/libxpt/xptinfo/Makefile.in | 4 +- mozilla/xpcom/libxpt/xptinfo/public/xpt_cpp.h | 4 +- .../libxpt/xptinfo/src/nsInterfaceInfo.cpp | 45 +- .../libxpt/xptinfo/src/nsInterfaceInfo.h | 11 +- .../xptinfo/src/nsInterfaceInfoManager.cpp | 528 +++++++++++++----- .../xptinfo/src/nsInterfaceInfoManager.h | 38 +- .../libxpt/xptinfo/src/nsXPTParamInfo.cpp | 71 ++- .../xptinfo/tests/TestInterfaceInfo.cpp | 46 +- mozilla/xpcom/reflect/xptinfo/Makefile.in | 4 +- .../xpcom/reflect/xptinfo/public/xpt_cpp.h | 4 +- .../reflect/xptinfo/src/nsInterfaceInfo.cpp | 45 +- .../reflect/xptinfo/src/nsInterfaceInfo.h | 11 +- .../xptinfo/src/nsInterfaceInfoManager.cpp | 528 +++++++++++++----- .../xptinfo/src/nsInterfaceInfoManager.h | 38 +- .../reflect/xptinfo/src/nsXPTParamInfo.cpp | 71 ++- .../xptinfo/tests/TestInterfaceInfo.cpp | 46 +- 16 files changed, 1118 insertions(+), 376 deletions(-) diff --git a/mozilla/xpcom/libxpt/xptinfo/Makefile.in b/mozilla/xpcom/libxpt/xptinfo/Makefile.in index 08e3adde319..dcf48ad5767 100644 --- a/mozilla/xpcom/libxpt/xptinfo/Makefile.in +++ b/mozilla/xpcom/libxpt/xptinfo/Makefile.in @@ -23,6 +23,8 @@ include $(DEPTH)/config/autoconf.mk DIRS = public src -DIRS += tests +ifdef ENABLE_TESTS +DIRS += tests +endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/xpcom/libxpt/xptinfo/public/xpt_cpp.h b/mozilla/xpcom/libxpt/xptinfo/public/xpt_cpp.h index 680086c4ae0..acdf01f4bd7 100644 --- a/mozilla/xpcom/libxpt/xptinfo/public/xpt_cpp.h +++ b/mozilla/xpcom/libxpt/xptinfo/public/xpt_cpp.h @@ -115,10 +115,10 @@ public: // is associated with so that we can find the table this index indexes // and then find the referenced XPTInterfaceDirectoryEntry so that we can // find (or build) the appropriate nsIInterfaceInfo. Simple :) - nsIInterfaceInfo* GetInterface() const ; + nsIInterfaceInfo* GetInterface(XPTInterfaceDirectoryEntry *entry) const ; // a *little* simpler than the above - const nsIID* GetInterfaceIID() const ; + const nsIID* GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const ; private: nsXPTParamInfo(); // no implementation diff --git a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.cpp b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.cpp index 62df0979b07..b45886f0af9 100644 --- a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.cpp +++ b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.cpp @@ -31,23 +31,22 @@ static NS_DEFINE_IID(kIInterfaceInfoIID, NS_IINTERFACEINFO_IID); NS_IMPL_ISUPPORTS(nsInterfaceInfo, kIInterfaceInfoIID); nsInterfaceInfo::nsInterfaceInfo(XPTInterfaceDirectoryEntry* entry, - nsInterfaceInfo *parent) + nsInterfaceInfo *parent) : mEntry(entry), mParent(parent) { NS_INIT_REFCNT(); NS_ADDREF_THIS(); - if(mParent) + if(mParent != NULL) { NS_ADDREF(mParent); - if(mParent) { mMethodBaseIndex = mParent->mMethodBaseIndex + mParent->mMethodCount; mConstantBaseIndex = mParent->mConstantBaseIndex + mParent->mConstantCount; - } - else + } else { mMethodBaseIndex = mConstantBaseIndex = 0; + } mMethodCount = mEntry->interface_descriptor->num_methods; mConstantCount = mEntry->interface_descriptor->num_constants; @@ -55,7 +54,7 @@ nsInterfaceInfo::nsInterfaceInfo(XPTInterfaceDirectoryEntry* entry, nsInterfaceInfo::~nsInterfaceInfo() { - if(mParent) + if(mParent != NULL) NS_RELEASE(mParent); } @@ -134,11 +133,10 @@ NS_IMETHODIMP nsInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) { NS_PRECONDITION(info, "bad param"); - if(index < mMethodBaseIndex) + if (index < mMethodBaseIndex) return mParent->GetMethodInfo(index, info); - if(index >= mMethodBaseIndex + mMethodCount) - { + if (index >= mMethodBaseIndex + mMethodCount) { NS_PRECONDITION(0, "bad param"); *info = NULL; return NS_ERROR_INVALID_ARG; @@ -146,8 +144,8 @@ nsInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) // else... *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, - &mEntry->interface_descriptor-> - method_descriptors[index - mMethodBaseIndex]); + &mEntry->interface_descriptor-> + method_descriptors[index - mMethodBaseIndex]); return NS_OK; } @@ -155,11 +153,10 @@ NS_IMETHODIMP nsInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant) { NS_PRECONDITION(constant, "bad param"); - if(index < mConstantBaseIndex) + if (index < mConstantBaseIndex) return mParent->GetConstant(index, constant); - if(index >= mConstantBaseIndex + mConstantCount) - { + if (index >= mConstantBaseIndex + mConstantCount) { NS_PRECONDITION(0, "bad param"); *constant = NULL; return NS_ERROR_INVALID_ARG; @@ -167,7 +164,23 @@ nsInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant) // else... *constant = NS_REINTERPRET_CAST(nsXPTConstant*, - &mEntry->interface_descriptor-> - const_descriptors[index-mConstantBaseIndex]); + &mEntry->interface_descriptor-> + const_descriptors[index-mConstantBaseIndex]); return NS_OK; } + +#ifdef DEBUG +#include +void +nsInterfaceInfo::print(FILE *fd) +{ + fprintf(fd, "iid: %s name: %s name_space: %s\n", + mEntry->iid.ToString(), + mEntry->name, + mEntry->name_space); + if (mParent != NULL) { + fprintf(fd, "parent:\n\t"); + mParent->print(fd); + } +} +#endif diff --git a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.h b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.h index 19c1afd6b70..1e4436016ca 100644 --- a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.h +++ b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfo.h @@ -23,6 +23,10 @@ #include "xpt_struct.h" #include "xpt_cpp.h" +#ifdef DEBUG +#include +#endif + // XXX destroy this! class nsInterfaceInfo : public nsIInterfaceInfo { @@ -48,10 +52,12 @@ class nsInterfaceInfo : public nsIInterfaceInfo public: virtual ~nsInterfaceInfo(); - // should be private - XPTInterfaceDirectoryEntry* mEntry; +#ifdef DEBUG + void print(FILE *fd); +#endif private: + XPTInterfaceDirectoryEntry* mEntry; nsInterfaceInfo* mParent; uint16 mMethodBaseIndex; @@ -60,5 +66,4 @@ private: uint16 mConstantCount; }; - #endif /* nsInterfaceInfo_h___ */ diff --git a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.cpp b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.cpp index a06ec99ab16..1a35b0c3a5e 100644 --- a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.cpp +++ b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.cpp @@ -29,71 +29,14 @@ #include "nsInterfaceInfo.h" #include "xptinfo.h" +#include "prio.h" +#include "plstr.h" +#include "prenv.h" + // this after nsISupports, to pick up IID // so that xpt stuff doesn't try to define it itself... -// #include "xpt_struct.h" #include "xpt_xdr.h" -// should get multiple xpt files from some well-known dir. -#define XPTFILE "simple.xpt" - -// Stolen from xpt_dump.c -// todo - lazy loading of file, etc. -XPTHeader *getheader() { - XPTState *state; - XPTCursor curs, *cursor = &curs; - XPTHeader *header; - struct stat file_stat; - int flen; - char *whole; - FILE *in; - - if (stat(XPTFILE, &file_stat) != 0) { - perror("FAILED: fstat"); - return NULL; - } - flen = file_stat.st_size; - in = fopen(XPTFILE, "rb"); - - if (!in) { - perror("FAILED: fopen"); - return NULL; - } - - whole = (char *)malloc(flen); - if (!whole) { - perror("FAILED: malloc for whole"); - return NULL; - } - - if (flen > 0) { - fread(whole, flen, 1, in); - state = XPT_NewXDRState(XPT_DECODE, whole, flen); - if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { - fprintf(stdout, "MakeCursor failed\n"); - return NULL; - } - if (!XPT_DoHeader(cursor, &header)) { - fprintf(stdout, "DoHeader failed\n"); - return NULL; - } - - free(header); - - XPT_DestroyXDRState(state); - // assum'd to be OK - free(whole); - fclose(in); - return header; - } - - free(whole); - fclose(in); - return NULL; -} - - - static NS_DEFINE_IID(kIIIManagerIID, NS_IINTERFACEINFO_MANAGER_IID); NS_IMPL_ISUPPORTS(nsInterfaceInfoManager, kIIIManagerIID); @@ -139,53 +82,279 @@ nsInterfaceInfoManager::nsInterfaceInfoManager() NS_INIT_REFCNT(); NS_ADDREF_THIS(); - mInfoArray = (nsInterfaceInfo**) calloc(HACK_CACHE_SIZE, sizeof(void*)); - - mHeader = getheader(); - PR_ASSERT((mHeader != NULL)); - nsServiceManager::GetService(kAllocatorCID, kIAllocatorIID, (nsISupports **)&mAllocator); PR_ASSERT((mAllocator != NULL)); + + initInterfaceTables(); } -nsInterfaceInfo * -nsInterfaceInfoManager::buildII(XPTInterfaceDirectoryEntry *entry) { - int i; - for (i = 0; i < HACK_CACHE_SIZE; i++) { - if (mInfoArray[i] == NULL) - break; - if (mInfoArray[i]->mEntry == entry) - return mInfoArray[i]; +// Stolen and modified from xpt_dump.c +XPTHeader *getHeader(const char *filename) { + XPTState *state = NULL; + XPTCursor curs, *cursor = &curs; + XPTHeader *header = NULL; + PRFileInfo fileinfo; + PRUint32 flen; + char *whole = NULL; + PRFileDesc *in = NULL; + + if (PR_GetFileInfo(filename, &fileinfo) != PR_SUCCESS) { + NS_ERROR("PR_GetFileInfo failed"); + return NULL; + } + flen = fileinfo.size; + + whole = (char *)malloc(flen); + if (!whole) { + NS_ERROR("FAILED: malloc for whole"); + return NULL; } - // ok, no dice. Does it have a parent? - nsInterfaceInfo *parent = NULL; - if (entry->interface_descriptor->parent_interface != NULL) { - for (i = 0; i < HACK_CACHE_SIZE; i++) { - if (mInfoArray[i] == NULL) - break; - if (mInfoArray[i]->mEntry == - entry->interface_descriptor->parent_interface) - parent = mInfoArray[i]; + // XXX changed this to PR_OPEN; does this do binary for windows? ("b") +// in = fopen(filename, "rb"); + in = PR_Open(filename, PR_RDONLY, 0); + if (!in) { + NS_ERROR("FAILED: fopen"); + goto out; + } + + if (flen > 0) { + PRInt32 howmany = PR_Read(in, whole, flen); + if (howmany < 0) { + NS_ERROR("FAILED: reading typelib file"); + goto out; + } + + // XXX lengths are PRUInt32, reads are PRInt32? + if (howmany < flen) { + NS_ERROR("short read of typelib file"); + goto out; + } + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + NS_ERROR("MakeCursor failed\n"); + goto out; + } + if (!XPT_DoHeader(cursor, &header)) { + NS_ERROR("DoHeader failed\n"); + goto out; } - if (parent == NULL) - parent = buildII(entry->interface_descriptor->parent_interface); - PR_ASSERT(parent); } - - nsInterfaceInfo *result = new nsInterfaceInfo(entry, parent); - while (mInfoArray[i] == NULL) - i++; - PR_ASSERT(i < HACK_CACHE_SIZE); - mInfoArray[i] = result; - - return result; + out: + if (state != NULL) + XPT_DestroyXDRState(state); + if (whole != NULL) + free(whole); + if (in != NULL) + PR_Close(in); + return header; } +static void +indexify_file(const char *filename, + PLHashTable *interfaceTable, + PLHashTable *typelibTable, + nsHashtable *IIDTable, + nsIAllocator *al) +{ + XPTHeader *header = getHeader(filename); + + int limit = header->num_interfaces; + + interface_record *value; +#ifdef DEBUG_mccabe + static int which = 0; + which++; +#endif + for (int i = 0; i < limit; i++) { + XPTInterfaceDirectoryEntry *current = header->interface_directory + i; + + // associate the current entry with the header it came from. + PL_HashTableAdd(typelibTable, current, header); + +#ifdef DEBUG_mccabe + fprintf(stderr, "%s", current->name); +#endif + // first try to look it up... + value = (interface_record *)PL_HashTableLookup(interfaceTable, + current->name); + // if none found, make a dummy record. + if (value == NULL) { + value = new interface_record(); + value->which_header = NULL; + value->resolved = PR_FALSE; + value->which = -1; + value->entry = NULL; + value->info = NULL; + void *hashEntry = + PL_HashTableAdd(interfaceTable, current->name, value); +#ifdef DEBUG_mccabe + fprintf(stderr, "... added, %d\n", which); +#endif + NS_ASSERTION(hashEntry != NULL, "PL_HashTableAdd failed?"); + } +#ifdef DEBUG_MCCABE + else { + fprintf(stderr, "... found, %d\n", value->which); + } +#endif + + // save info from the interface in the global table. if it's resolved. + if (current->interface_descriptor != NULL) { + // we claim it should only be defined once. XXX ? + NS_ASSERTION(value->which_header == NULL, + "some interface def'd in multiple typelibs."); + value->which_header = header; + value->resolved = PR_TRUE; + value->which = which; + value->entry = current; + + // XXX is this a leak? + nsIDKey idKey(current->iid); +#ifdef DEBUG + char * found_name; + found_name = (char *)IIDTable->Get(&idKey); + NS_ASSERTION(found_name == NULL, + "iid already associated with a name?"); +#endif + IIDTable->Put(&idKey, current->name); +#ifdef DEBUG_mccabe + fprintf(stderr, "\t... resolved, %d\n", value->which); +#endif + } + } +} + +// as many InterfaceDirectoryEntries as we expect to see. +#define XPT_HASHSIZE 64 + +#ifdef DEBUG +static PRIntn +check_enumerator(PLHashEntry *he, PRIntn index, void *arg); +#endif + +static PLHashNumber +hash_by_value(const void *key) { + return (uint32)key; +} + +void nsInterfaceInfoManager::initInterfaceTables() +{ + // make a hashtable to associate names with arbitrary info + this->mInterfaceTable = PL_NewHashTable(XPT_HASHSIZE, + PL_HashString, // hash keys + PL_CompareStrings, // compare keys + PL_CompareValues, // comp values + NULL, NULL); + + // make a hashtable to associate InterfaceDirectoryEntry values + // with XPTHeaders. (for nsXPTParamInfo::GetInterface) + this->mTypelibTable = PL_NewHashTable(XPT_HASHSIZE, + hash_by_value, + PL_CompareValues, + PL_CompareValues, + NULL, NULL); + + // make a hashtable to map iids to names + this->mIIDTable = new nsHashtable(XPT_HASHSIZE); + + // First, find the xpt directory from the env. + // XXX don't free this? + char *xptdirname = PR_GetEnv("XPTDIR"); + NS_ASSERTION(xptdirname != NULL, + "set env var XPTDIR to a directory containg .xpt files."); + + // now loop thru the xpt files in the directory. + + // XXX This code stolen with few modifications from nsRepository; any + // point in doing it through them instead?) + + PRDir *xptdir = PR_OpenDir(xptdirname); + if (xptdir == NULL) { + NS_ERROR("Couldn't open XPT directory"); + return; // XXX fail gigantically. + } + + // Create a buffer that has dir/ in it so we can append + // the filename each time in the loop + char fullname[1024]; // NS_MAX_FILENAME_LEN + PL_strncpyz(fullname, xptdirname, sizeof(fullname)); + unsigned int n = strlen(fullname); + if (n+1 < sizeof(fullname)) { + fullname[n] = '/'; + n++; + } + char *filepart = fullname + n; + + PRDirEntry *dirent = NULL; +#ifdef DEBUG_mccabe + int which = 0; +#endif + while ((dirent = PR_ReadDir(xptdir, PR_SKIP_BOTH)) != NULL) { + PL_strncpyz(filepart, dirent->name, sizeof(fullname)-n); + PRFileInfo statbuf; + // stattable? + if (PR_GetFileInfo(fullname,&statbuf) != PR_SUCCESS) + continue; + // plain file? + else if (statbuf.type != PR_FILE_FILE) + continue; + // .xpt suffix? + int flen = PL_strlen(fullname); + if (flen >= 4 && !PL_strcasecmp(&(fullname[flen - 4]), ".xpt")) { + // it's a valid file, read it in. +#ifdef DEBUG_mccabe + which++; + fprintf(stderr, "%d %s\n", which, fullname); +#endif + indexify_file(fullname, + this->mInterfaceTable, + this->mTypelibTable, + this->mIIDTable, + this->mAllocator); + } else { + continue; + } + } + PR_CloseDir(xptdir); + +#ifdef DEBUG + // scan here to confirm that all interfaces are resolved. + PL_HashTableEnumerateEntries(this->mInterfaceTable, + check_enumerator, + this->mIIDTable); +#endif +} + +#ifdef DEBUG +PRIntn check_enumerator(PLHashEntry *he, PRIntn index, void *arg) { + char *key = (char *)he->key; + interface_record *value = (interface_record *)he->value; + nsHashtable *iidtable = (nsHashtable *)arg; + + + if (value->resolved == PR_FALSE) { + fprintf(stderr, "unresolved interface %s\n", key); + } else { + NS_ASSERTION(value->entry, "resolved, but no entry?"); + nsIDKey idKey(value->entry->iid); + char *name_from_iid = (char *)iidtable->Get(&idKey); + NS_ASSERTION(name_from_iid != NULL, + "no name assoc'd with iid for entry for name?"); + + // XXX note that below is only ncc'ly the case if xdr doesn't give us + // duplicated strings. +// NS_ASSERTION(name_from_iid == key, +// "key and iid name xpected to be same"); + } + return HT_ENUMERATE_NEXT; +} +#endif + nsInterfaceInfoManager::~nsInterfaceInfoManager() { // let the singleton leak @@ -193,76 +362,115 @@ nsInterfaceInfoManager::~nsInterfaceInfoManager() NS_IMETHODIMP nsInterfaceInfoManager::GetInfoForIID(const nsIID* iid, - nsIInterfaceInfo** info) + nsIInterfaceInfo** info) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (iid->Equals(entry->iid)) { - *info = buildII(entry); - NS_ADDREF(*info); - return NS_OK; - } - } - *info = NULL; - return NS_ERROR_FAILURE; + nsIDKey idKey(*iid); + char *result_name = (char *)this->mIIDTable->Get(&idKey); + + return this->GetInfoForName(result_name, info); } NS_IMETHODIMP nsInterfaceInfoManager::GetInfoForName(const char* name, - nsIInterfaceInfo** info) + nsIInterfaceInfo** info) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (!strcmp(name, entry->name)) { - *info = buildII(entry); - NS_ADDREF(*info); - return NS_OK; + interface_record *record = + (interface_record *)PL_HashTableLookup(this->mInterfaceTable, name); + if (record == NULL || record->resolved == PR_FALSE) { + *info = NULL; + return NS_ERROR_FAILURE; + } + PR_ASSERT(record->entry != NULL); + + // Is there already an II obj associated with the interface_record? + if (record->info != NULL) { + // yay! + *info = record->info; + NS_ADDREF(*info); + return NS_OK; + } + + // nope, better make one. first, find a parent for it. + nsIInterfaceInfo *parent; + XPTInterfaceDirectoryEntry *entry = record->entry; + uint16 parent_index = entry->interface_descriptor->parent_interface; + // Does it _get_ a parent? (is it nsISupports?) + if (parent_index == 0) { + // presumably this is only the case for nsISupports. + parent = NULL; + } else { + // there's a parent index that points to an entry in the same table + // that this one was defined in. Accounting for magic offset. + XPTInterfaceDirectoryEntry *parent_entry = + record->which_header->interface_directory + parent_index - 1; + // get a name from it (which should never be null) and build + // that. XXX OPT Hm, could have a helper function to avoid + // second lookup if this entry happens to be resolved. + nsresult nsr = GetInfoForName(parent_entry->name, &parent); + if (NS_IS_ERROR(nsr)) { + *info = NULL; + return NS_ERROR_FAILURE; } } - *info = NULL; - return NS_ERROR_FAILURE; + + // got a parent for it, now build the object itself + nsInterfaceInfo *result = + new nsInterfaceInfo(entry, (nsInterfaceInfo *)parent); + *info = result; + NS_ADDREF(*info); + return NS_OK; } NS_IMETHODIMP nsInterfaceInfoManager::GetIIDForName(const char* name, nsIID** iid) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (!strcmp(name, entry->name)) { - nsIID* p; - - - if(!(p = (nsIID*)mAllocator->Alloc(sizeof(nsIID)))) - break; - - // XXX I'm confused here about the lifetime of IID pointers. - memcpy(p, &entry->iid, sizeof(nsIID)); - *iid = p; - return NS_OK; - } + interface_record *record = + (interface_record *)PL_HashTableLookup(this->mInterfaceTable, name); + if (record == NULL || record->resolved == PR_FALSE) { + *iid = NULL; + return NS_ERROR_FAILURE; } - *iid = NULL; - return NS_ERROR_FAILURE; + PR_ASSERT(record->entry != NULL); + + nsIID* p; + if(!(p = (nsIID *)mAllocator->Alloc(sizeof(nsIID)))) + return NS_ERROR_FAILURE; + + // XXX I'm confused here about the lifetime of IID pointers. + memcpy(p, &record->entry->iid, sizeof(nsIID)); + *iid = p; + return NS_OK; } NS_IMETHODIMP nsInterfaceInfoManager::GetNameForIID(const nsIID* iid, char** name) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (iid->Equals(entry->iid)) { - char* p; - int len = strlen(entry->name)+1; - if(!(p = (char*)mAllocator->Alloc(len))) - break; - memcpy(p, &entry->name, len); - *name = p; - return NS_OK; - } + nsIDKey idKey(*iid); + char *result_name = (char *)this->mIIDTable->Get(&idKey); + +#ifdef DEBUG + // XXX assert here that lookup in table matches iid? + nsIID *newid; + nsresult isok = GetIIDForName(result_name, &newid); + PR_ASSERT(newid->Equals(*newid)); + PR_ASSERT(isok == NS_OK); +#endif + + if (result_name == NULL) { + *name = NULL; + return NS_ERROR_FAILURE; } - *name = NULL; - return NS_ERROR_FAILURE; -} + + char *p; + int len = strlen(result_name) + 1; + if(!(p = (char *)mAllocator->Alloc(len))) { + *name = NULL; + return NS_ERROR_FAILURE; + } + memcpy(p, result_name, len); + *name = p; + return NS_OK; +} // XXX this goes away; IIM should be a service. // ... where does decl for this go? @@ -272,3 +480,35 @@ XPTI_GetInterfaceInfoManager() { return nsInterfaceInfoManager::GetInterfaceInfoManager(); } + +#if 0 +struct XPTInterfaceDirectoryEntry { + nsID iid; + char *name; + char *name_space; + XPTInterfaceDescriptor *interface_descriptor; +#if 0 /* not yet */ + /* not stored on disk */ + uint32 offset; /* the offset for an ID still to be read */ +#endif +}; + +struct XPTInterfaceDescriptor { + uint16 parent_interface; + uint16 num_methods; + XPTMethodDescriptor *method_descriptors; + uint16 num_constants; + XPTConstDescriptor *const_descriptors; +}; + +struct XPTHeader { + char magic[16]; + uint8 major_version; + uint8 minor_version; + uint16 num_interfaces; + uint32 file_length; + XPTInterfaceDirectoryEntry *interface_directory; + uint32 data_pool; + XPTAnnotation *annotations; +}; +#endif diff --git a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.h b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.h index 63c30f4c48f..4703e819513 100644 --- a/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.h +++ b/mozilla/xpcom/libxpt/xptinfo/src/nsInterfaceInfoManager.h @@ -28,6 +28,12 @@ #include "nsInterfaceInfo.h" +#include "nsHashtable.h" + +#include "plhash.h" + +class hash_record; + class nsInterfaceInfoManager : public nsIInterfaceInfoManager { NS_DECL_ISUPPORTS; @@ -48,13 +54,37 @@ public: static nsIAllocator* GetAllocator(nsInterfaceInfoManager* iim = NULL); private: - // temporary hack - nsInterfaceInfo **mInfoArray; - nsInterfaceInfo *buildII(XPTInterfaceDirectoryEntry *entry); + friend nsIInterfaceInfo* + nsXPTParamInfo::GetInterface(XPTInterfaceDirectoryEntry *entry) const; + friend const nsIID* + nsXPTParamInfo::GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const; + + void initInterfaceTables(); + + // mapping between names and records + PLHashTable *mInterfaceTable; + + // mapping between entries and typelibs (for nsXPTParamInfo::GetInterface) + PLHashTable *mTypelibTable; + + // mapping between iids and names + // (record handling is looked up by name; iids are translated there) + nsHashtable *mIIDTable; - XPTHeader *mHeader; nsInterfaceInfo *mParent; nsIAllocator* mAllocator; }; +// For references in the mInterfaceTable hashtable. +class interface_record { +public: + XPTHeader *which_header; + PRBool resolved; + int which; + XPTInterfaceDirectoryEntry *entry; + nsInterfaceInfo *info; +}; + + + #endif /* nsInterfaceInfoManager_h___ */ diff --git a/mozilla/xpcom/libxpt/xptinfo/src/nsXPTParamInfo.cpp b/mozilla/xpcom/libxpt/xptinfo/src/nsXPTParamInfo.cpp index 8c5d90165e7..61bdd6e2c82 100644 --- a/mozilla/xpcom/libxpt/xptinfo/src/nsXPTParamInfo.cpp +++ b/mozilla/xpcom/libxpt/xptinfo/src/nsXPTParamInfo.cpp @@ -16,8 +16,10 @@ * Reserved. */ -// Convienence bits of nsXPTParamInfo that don't fit into xpt_cpp.h -// flyweight wrappers. +/* + * Convienence bits of nsXPTParamInfo that don't fit into xpt_cpp.h + * flyweight wrappers. + */ #include "nsISupports.h" #include "nsIInterfaceInfoManager.h" @@ -31,26 +33,67 @@ // Placeholder - this implementation just returns NULL. nsIInterfaceInfo* -nsXPTParamInfo::GetInterface() const +nsXPTParamInfo::GetInterface(XPTInterfaceDirectoryEntry *entry) const { - NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE,"not an interface"); + NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE, + "not an interface"); nsIInterfaceInfoManager* mgr; if(!(mgr = nsInterfaceInfoManager::GetInterfaceInfoManager())) return NULL; + nsInterfaceInfoManager* mymgr = (nsInterfaceInfoManager *)mgr; -// nsIInterfaceInfo* info; -// mgr->GetInfoForIID(&InterfaceDirectoryEntryTable[type.type.interface].iid, -// &info); - NS_RELEASE(mgr); -// return info; - return NULL; + // what typelib did the entry come from? + XPTHeader *which_header = + (XPTHeader *)PL_HashTableLookup(mymgr->mTypelibTable, entry); + NS_ASSERTION(which_header != NULL, ""); + + // can't use IID, because it could be null for this entry. + char *interface_name; + interface_name = which_header->interface_directory[type.type.interface].name; + + nsIInterfaceInfo *info; + nsresult nsr = mymgr->GetInfoForName(interface_name, &info); + if (NS_IS_ERROR(nsr)) { + NS_RELEASE(mgr); + return NULL; + } + return info; } const nsIID* -nsXPTParamInfo::GetInterfaceIID() const +nsXPTParamInfo::GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const { - NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE,"not an interface"); -// return &InterfaceDirectoryEntryTable[type.type.interface].iid; - return (const nsIID*) NULL; + NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE, + "not an interface"); + + nsIInterfaceInfoManager* mgr; + if(!(mgr = nsInterfaceInfoManager::GetInterfaceInfoManager())) + return NULL; + nsInterfaceInfoManager* mymgr = (nsInterfaceInfoManager *)mgr; + + // what typelib did the entry come from? + XPTHeader *which_header = + (XPTHeader *)PL_HashTableLookup(mymgr->mTypelibTable, entry); + NS_ASSERTION(which_header != NULL, ""); + + // can't use IID, because it could be null for this entry. + char *interface_name; + interface_name = which_header->interface_directory[type.type.interface].name; + + nsIID* iid; + + nsresult nsr = mymgr->GetIIDForName(interface_name, &iid); + if (NS_IS_ERROR(nsr)) { + NS_RELEASE(mgr); + return NULL; + } + return iid; } + + + + + + + diff --git a/mozilla/xpcom/libxpt/xptinfo/tests/TestInterfaceInfo.cpp b/mozilla/xpcom/libxpt/xptinfo/tests/TestInterfaceInfo.cpp index 4f6a370a1ce..af7b2be2ab5 100644 --- a/mozilla/xpcom/libxpt/xptinfo/tests/TestInterfaceInfo.cpp +++ b/mozilla/xpcom/libxpt/xptinfo/tests/TestInterfaceInfo.cpp @@ -25,14 +25,54 @@ #include "nsIInterfaceInfoManager.h" #include "xptinfo.h" +#include + +#include "../src/nsInterfaceInfo.h" + static void RegAllocator(); int main (int argc, char **argv) { RegAllocator(); nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager(); - nsIID *iid; - iim->GetIIDForName("Interface", &iid); + nsIID *iid1, *iid2, *iid3, *iid4; + char *name1, *name2, *name3, *name4; + nsIInterfaceInfo *info1, *info2, *info3, *info4; + + fprintf(stderr, "\ngetting iid for 'Interface'\n"); + iim->GetIIDForName("Interface", &iid1); + iim->GetNameForIID(iid1, &name1); + fprintf(stderr, "%s iid %s\n", name1, iid1->ToString()); + + fprintf(stderr, "\ngetting iid for 'nsIBaseStream'\n"); + iim->GetIIDForName("nsIBaseStream", &iid2); + iim->GetNameForIID(iid2, &name2); + fprintf(stderr, "%s iid %s\n", name2, iid2->ToString()); + + fprintf(stderr, "iid: %s, name: %s\n", iid1->ToString(), name1); + fprintf(stderr, "iid: %s, name: %s\n", iid2->ToString(), name2); + + fprintf(stderr, "\ngetting info for iid2 from above\n"); + iim->GetInfoForIID(iid2, &info2); +#ifdef DEBUG + ((nsInterfaceInfo *)info2)->print(stderr); +#endif + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid3); + iim->GetNameForIID(iid3, &name3); + fprintf(stderr, "%s iid %s\n", name3, iid2->ToString()); + iim->GetInfoForIID(iid3, &info3); +#ifdef DEBUG + ((nsInterfaceInfo *)info3)->print(stderr); +#endif + + fprintf(stderr, "\ngetting info for name 'nsIBidirectionalEnumerator'\n"); + iim->GetInfoForName("nsIBidirectionalEnumerator", &info4); +#ifdef DEBUG + ((nsInterfaceInfo *)info4)->print(stderr); +#endif + return 0; } @@ -59,5 +99,3 @@ static void RegAllocator() nsRepository::RegisterComponent(kAllocatorCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE); } - - diff --git a/mozilla/xpcom/reflect/xptinfo/Makefile.in b/mozilla/xpcom/reflect/xptinfo/Makefile.in index 08e3adde319..dcf48ad5767 100644 --- a/mozilla/xpcom/reflect/xptinfo/Makefile.in +++ b/mozilla/xpcom/reflect/xptinfo/Makefile.in @@ -23,6 +23,8 @@ include $(DEPTH)/config/autoconf.mk DIRS = public src -DIRS += tests +ifdef ENABLE_TESTS +DIRS += tests +endif include $(topsrcdir)/config/rules.mk diff --git a/mozilla/xpcom/reflect/xptinfo/public/xpt_cpp.h b/mozilla/xpcom/reflect/xptinfo/public/xpt_cpp.h index 680086c4ae0..acdf01f4bd7 100644 --- a/mozilla/xpcom/reflect/xptinfo/public/xpt_cpp.h +++ b/mozilla/xpcom/reflect/xptinfo/public/xpt_cpp.h @@ -115,10 +115,10 @@ public: // is associated with so that we can find the table this index indexes // and then find the referenced XPTInterfaceDirectoryEntry so that we can // find (or build) the appropriate nsIInterfaceInfo. Simple :) - nsIInterfaceInfo* GetInterface() const ; + nsIInterfaceInfo* GetInterface(XPTInterfaceDirectoryEntry *entry) const ; // a *little* simpler than the above - const nsIID* GetInterfaceIID() const ; + const nsIID* GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const ; private: nsXPTParamInfo(); // no implementation diff --git a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.cpp b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.cpp index 62df0979b07..b45886f0af9 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.cpp +++ b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.cpp @@ -31,23 +31,22 @@ static NS_DEFINE_IID(kIInterfaceInfoIID, NS_IINTERFACEINFO_IID); NS_IMPL_ISUPPORTS(nsInterfaceInfo, kIInterfaceInfoIID); nsInterfaceInfo::nsInterfaceInfo(XPTInterfaceDirectoryEntry* entry, - nsInterfaceInfo *parent) + nsInterfaceInfo *parent) : mEntry(entry), mParent(parent) { NS_INIT_REFCNT(); NS_ADDREF_THIS(); - if(mParent) + if(mParent != NULL) { NS_ADDREF(mParent); - if(mParent) { mMethodBaseIndex = mParent->mMethodBaseIndex + mParent->mMethodCount; mConstantBaseIndex = mParent->mConstantBaseIndex + mParent->mConstantCount; - } - else + } else { mMethodBaseIndex = mConstantBaseIndex = 0; + } mMethodCount = mEntry->interface_descriptor->num_methods; mConstantCount = mEntry->interface_descriptor->num_constants; @@ -55,7 +54,7 @@ nsInterfaceInfo::nsInterfaceInfo(XPTInterfaceDirectoryEntry* entry, nsInterfaceInfo::~nsInterfaceInfo() { - if(mParent) + if(mParent != NULL) NS_RELEASE(mParent); } @@ -134,11 +133,10 @@ NS_IMETHODIMP nsInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) { NS_PRECONDITION(info, "bad param"); - if(index < mMethodBaseIndex) + if (index < mMethodBaseIndex) return mParent->GetMethodInfo(index, info); - if(index >= mMethodBaseIndex + mMethodCount) - { + if (index >= mMethodBaseIndex + mMethodCount) { NS_PRECONDITION(0, "bad param"); *info = NULL; return NS_ERROR_INVALID_ARG; @@ -146,8 +144,8 @@ nsInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) // else... *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, - &mEntry->interface_descriptor-> - method_descriptors[index - mMethodBaseIndex]); + &mEntry->interface_descriptor-> + method_descriptors[index - mMethodBaseIndex]); return NS_OK; } @@ -155,11 +153,10 @@ NS_IMETHODIMP nsInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant) { NS_PRECONDITION(constant, "bad param"); - if(index < mConstantBaseIndex) + if (index < mConstantBaseIndex) return mParent->GetConstant(index, constant); - if(index >= mConstantBaseIndex + mConstantCount) - { + if (index >= mConstantBaseIndex + mConstantCount) { NS_PRECONDITION(0, "bad param"); *constant = NULL; return NS_ERROR_INVALID_ARG; @@ -167,7 +164,23 @@ nsInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant) // else... *constant = NS_REINTERPRET_CAST(nsXPTConstant*, - &mEntry->interface_descriptor-> - const_descriptors[index-mConstantBaseIndex]); + &mEntry->interface_descriptor-> + const_descriptors[index-mConstantBaseIndex]); return NS_OK; } + +#ifdef DEBUG +#include +void +nsInterfaceInfo::print(FILE *fd) +{ + fprintf(fd, "iid: %s name: %s name_space: %s\n", + mEntry->iid.ToString(), + mEntry->name, + mEntry->name_space); + if (mParent != NULL) { + fprintf(fd, "parent:\n\t"); + mParent->print(fd); + } +} +#endif diff --git a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.h b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.h index 19c1afd6b70..1e4436016ca 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.h +++ b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfo.h @@ -23,6 +23,10 @@ #include "xpt_struct.h" #include "xpt_cpp.h" +#ifdef DEBUG +#include +#endif + // XXX destroy this! class nsInterfaceInfo : public nsIInterfaceInfo { @@ -48,10 +52,12 @@ class nsInterfaceInfo : public nsIInterfaceInfo public: virtual ~nsInterfaceInfo(); - // should be private - XPTInterfaceDirectoryEntry* mEntry; +#ifdef DEBUG + void print(FILE *fd); +#endif private: + XPTInterfaceDirectoryEntry* mEntry; nsInterfaceInfo* mParent; uint16 mMethodBaseIndex; @@ -60,5 +66,4 @@ private: uint16 mConstantCount; }; - #endif /* nsInterfaceInfo_h___ */ diff --git a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.cpp b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.cpp index a06ec99ab16..1a35b0c3a5e 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.cpp +++ b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.cpp @@ -29,71 +29,14 @@ #include "nsInterfaceInfo.h" #include "xptinfo.h" +#include "prio.h" +#include "plstr.h" +#include "prenv.h" + // this after nsISupports, to pick up IID // so that xpt stuff doesn't try to define it itself... -// #include "xpt_struct.h" #include "xpt_xdr.h" -// should get multiple xpt files from some well-known dir. -#define XPTFILE "simple.xpt" - -// Stolen from xpt_dump.c -// todo - lazy loading of file, etc. -XPTHeader *getheader() { - XPTState *state; - XPTCursor curs, *cursor = &curs; - XPTHeader *header; - struct stat file_stat; - int flen; - char *whole; - FILE *in; - - if (stat(XPTFILE, &file_stat) != 0) { - perror("FAILED: fstat"); - return NULL; - } - flen = file_stat.st_size; - in = fopen(XPTFILE, "rb"); - - if (!in) { - perror("FAILED: fopen"); - return NULL; - } - - whole = (char *)malloc(flen); - if (!whole) { - perror("FAILED: malloc for whole"); - return NULL; - } - - if (flen > 0) { - fread(whole, flen, 1, in); - state = XPT_NewXDRState(XPT_DECODE, whole, flen); - if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { - fprintf(stdout, "MakeCursor failed\n"); - return NULL; - } - if (!XPT_DoHeader(cursor, &header)) { - fprintf(stdout, "DoHeader failed\n"); - return NULL; - } - - free(header); - - XPT_DestroyXDRState(state); - // assum'd to be OK - free(whole); - fclose(in); - return header; - } - - free(whole); - fclose(in); - return NULL; -} - - - static NS_DEFINE_IID(kIIIManagerIID, NS_IINTERFACEINFO_MANAGER_IID); NS_IMPL_ISUPPORTS(nsInterfaceInfoManager, kIIIManagerIID); @@ -139,53 +82,279 @@ nsInterfaceInfoManager::nsInterfaceInfoManager() NS_INIT_REFCNT(); NS_ADDREF_THIS(); - mInfoArray = (nsInterfaceInfo**) calloc(HACK_CACHE_SIZE, sizeof(void*)); - - mHeader = getheader(); - PR_ASSERT((mHeader != NULL)); - nsServiceManager::GetService(kAllocatorCID, kIAllocatorIID, (nsISupports **)&mAllocator); PR_ASSERT((mAllocator != NULL)); + + initInterfaceTables(); } -nsInterfaceInfo * -nsInterfaceInfoManager::buildII(XPTInterfaceDirectoryEntry *entry) { - int i; - for (i = 0; i < HACK_CACHE_SIZE; i++) { - if (mInfoArray[i] == NULL) - break; - if (mInfoArray[i]->mEntry == entry) - return mInfoArray[i]; +// Stolen and modified from xpt_dump.c +XPTHeader *getHeader(const char *filename) { + XPTState *state = NULL; + XPTCursor curs, *cursor = &curs; + XPTHeader *header = NULL; + PRFileInfo fileinfo; + PRUint32 flen; + char *whole = NULL; + PRFileDesc *in = NULL; + + if (PR_GetFileInfo(filename, &fileinfo) != PR_SUCCESS) { + NS_ERROR("PR_GetFileInfo failed"); + return NULL; + } + flen = fileinfo.size; + + whole = (char *)malloc(flen); + if (!whole) { + NS_ERROR("FAILED: malloc for whole"); + return NULL; } - // ok, no dice. Does it have a parent? - nsInterfaceInfo *parent = NULL; - if (entry->interface_descriptor->parent_interface != NULL) { - for (i = 0; i < HACK_CACHE_SIZE; i++) { - if (mInfoArray[i] == NULL) - break; - if (mInfoArray[i]->mEntry == - entry->interface_descriptor->parent_interface) - parent = mInfoArray[i]; + // XXX changed this to PR_OPEN; does this do binary for windows? ("b") +// in = fopen(filename, "rb"); + in = PR_Open(filename, PR_RDONLY, 0); + if (!in) { + NS_ERROR("FAILED: fopen"); + goto out; + } + + if (flen > 0) { + PRInt32 howmany = PR_Read(in, whole, flen); + if (howmany < 0) { + NS_ERROR("FAILED: reading typelib file"); + goto out; + } + + // XXX lengths are PRUInt32, reads are PRInt32? + if (howmany < flen) { + NS_ERROR("short read of typelib file"); + goto out; + } + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + NS_ERROR("MakeCursor failed\n"); + goto out; + } + if (!XPT_DoHeader(cursor, &header)) { + NS_ERROR("DoHeader failed\n"); + goto out; } - if (parent == NULL) - parent = buildII(entry->interface_descriptor->parent_interface); - PR_ASSERT(parent); } - - nsInterfaceInfo *result = new nsInterfaceInfo(entry, parent); - while (mInfoArray[i] == NULL) - i++; - PR_ASSERT(i < HACK_CACHE_SIZE); - mInfoArray[i] = result; - - return result; + out: + if (state != NULL) + XPT_DestroyXDRState(state); + if (whole != NULL) + free(whole); + if (in != NULL) + PR_Close(in); + return header; } +static void +indexify_file(const char *filename, + PLHashTable *interfaceTable, + PLHashTable *typelibTable, + nsHashtable *IIDTable, + nsIAllocator *al) +{ + XPTHeader *header = getHeader(filename); + + int limit = header->num_interfaces; + + interface_record *value; +#ifdef DEBUG_mccabe + static int which = 0; + which++; +#endif + for (int i = 0; i < limit; i++) { + XPTInterfaceDirectoryEntry *current = header->interface_directory + i; + + // associate the current entry with the header it came from. + PL_HashTableAdd(typelibTable, current, header); + +#ifdef DEBUG_mccabe + fprintf(stderr, "%s", current->name); +#endif + // first try to look it up... + value = (interface_record *)PL_HashTableLookup(interfaceTable, + current->name); + // if none found, make a dummy record. + if (value == NULL) { + value = new interface_record(); + value->which_header = NULL; + value->resolved = PR_FALSE; + value->which = -1; + value->entry = NULL; + value->info = NULL; + void *hashEntry = + PL_HashTableAdd(interfaceTable, current->name, value); +#ifdef DEBUG_mccabe + fprintf(stderr, "... added, %d\n", which); +#endif + NS_ASSERTION(hashEntry != NULL, "PL_HashTableAdd failed?"); + } +#ifdef DEBUG_MCCABE + else { + fprintf(stderr, "... found, %d\n", value->which); + } +#endif + + // save info from the interface in the global table. if it's resolved. + if (current->interface_descriptor != NULL) { + // we claim it should only be defined once. XXX ? + NS_ASSERTION(value->which_header == NULL, + "some interface def'd in multiple typelibs."); + value->which_header = header; + value->resolved = PR_TRUE; + value->which = which; + value->entry = current; + + // XXX is this a leak? + nsIDKey idKey(current->iid); +#ifdef DEBUG + char * found_name; + found_name = (char *)IIDTable->Get(&idKey); + NS_ASSERTION(found_name == NULL, + "iid already associated with a name?"); +#endif + IIDTable->Put(&idKey, current->name); +#ifdef DEBUG_mccabe + fprintf(stderr, "\t... resolved, %d\n", value->which); +#endif + } + } +} + +// as many InterfaceDirectoryEntries as we expect to see. +#define XPT_HASHSIZE 64 + +#ifdef DEBUG +static PRIntn +check_enumerator(PLHashEntry *he, PRIntn index, void *arg); +#endif + +static PLHashNumber +hash_by_value(const void *key) { + return (uint32)key; +} + +void nsInterfaceInfoManager::initInterfaceTables() +{ + // make a hashtable to associate names with arbitrary info + this->mInterfaceTable = PL_NewHashTable(XPT_HASHSIZE, + PL_HashString, // hash keys + PL_CompareStrings, // compare keys + PL_CompareValues, // comp values + NULL, NULL); + + // make a hashtable to associate InterfaceDirectoryEntry values + // with XPTHeaders. (for nsXPTParamInfo::GetInterface) + this->mTypelibTable = PL_NewHashTable(XPT_HASHSIZE, + hash_by_value, + PL_CompareValues, + PL_CompareValues, + NULL, NULL); + + // make a hashtable to map iids to names + this->mIIDTable = new nsHashtable(XPT_HASHSIZE); + + // First, find the xpt directory from the env. + // XXX don't free this? + char *xptdirname = PR_GetEnv("XPTDIR"); + NS_ASSERTION(xptdirname != NULL, + "set env var XPTDIR to a directory containg .xpt files."); + + // now loop thru the xpt files in the directory. + + // XXX This code stolen with few modifications from nsRepository; any + // point in doing it through them instead?) + + PRDir *xptdir = PR_OpenDir(xptdirname); + if (xptdir == NULL) { + NS_ERROR("Couldn't open XPT directory"); + return; // XXX fail gigantically. + } + + // Create a buffer that has dir/ in it so we can append + // the filename each time in the loop + char fullname[1024]; // NS_MAX_FILENAME_LEN + PL_strncpyz(fullname, xptdirname, sizeof(fullname)); + unsigned int n = strlen(fullname); + if (n+1 < sizeof(fullname)) { + fullname[n] = '/'; + n++; + } + char *filepart = fullname + n; + + PRDirEntry *dirent = NULL; +#ifdef DEBUG_mccabe + int which = 0; +#endif + while ((dirent = PR_ReadDir(xptdir, PR_SKIP_BOTH)) != NULL) { + PL_strncpyz(filepart, dirent->name, sizeof(fullname)-n); + PRFileInfo statbuf; + // stattable? + if (PR_GetFileInfo(fullname,&statbuf) != PR_SUCCESS) + continue; + // plain file? + else if (statbuf.type != PR_FILE_FILE) + continue; + // .xpt suffix? + int flen = PL_strlen(fullname); + if (flen >= 4 && !PL_strcasecmp(&(fullname[flen - 4]), ".xpt")) { + // it's a valid file, read it in. +#ifdef DEBUG_mccabe + which++; + fprintf(stderr, "%d %s\n", which, fullname); +#endif + indexify_file(fullname, + this->mInterfaceTable, + this->mTypelibTable, + this->mIIDTable, + this->mAllocator); + } else { + continue; + } + } + PR_CloseDir(xptdir); + +#ifdef DEBUG + // scan here to confirm that all interfaces are resolved. + PL_HashTableEnumerateEntries(this->mInterfaceTable, + check_enumerator, + this->mIIDTable); +#endif +} + +#ifdef DEBUG +PRIntn check_enumerator(PLHashEntry *he, PRIntn index, void *arg) { + char *key = (char *)he->key; + interface_record *value = (interface_record *)he->value; + nsHashtable *iidtable = (nsHashtable *)arg; + + + if (value->resolved == PR_FALSE) { + fprintf(stderr, "unresolved interface %s\n", key); + } else { + NS_ASSERTION(value->entry, "resolved, but no entry?"); + nsIDKey idKey(value->entry->iid); + char *name_from_iid = (char *)iidtable->Get(&idKey); + NS_ASSERTION(name_from_iid != NULL, + "no name assoc'd with iid for entry for name?"); + + // XXX note that below is only ncc'ly the case if xdr doesn't give us + // duplicated strings. +// NS_ASSERTION(name_from_iid == key, +// "key and iid name xpected to be same"); + } + return HT_ENUMERATE_NEXT; +} +#endif + nsInterfaceInfoManager::~nsInterfaceInfoManager() { // let the singleton leak @@ -193,76 +362,115 @@ nsInterfaceInfoManager::~nsInterfaceInfoManager() NS_IMETHODIMP nsInterfaceInfoManager::GetInfoForIID(const nsIID* iid, - nsIInterfaceInfo** info) + nsIInterfaceInfo** info) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (iid->Equals(entry->iid)) { - *info = buildII(entry); - NS_ADDREF(*info); - return NS_OK; - } - } - *info = NULL; - return NS_ERROR_FAILURE; + nsIDKey idKey(*iid); + char *result_name = (char *)this->mIIDTable->Get(&idKey); + + return this->GetInfoForName(result_name, info); } NS_IMETHODIMP nsInterfaceInfoManager::GetInfoForName(const char* name, - nsIInterfaceInfo** info) + nsIInterfaceInfo** info) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (!strcmp(name, entry->name)) { - *info = buildII(entry); - NS_ADDREF(*info); - return NS_OK; + interface_record *record = + (interface_record *)PL_HashTableLookup(this->mInterfaceTable, name); + if (record == NULL || record->resolved == PR_FALSE) { + *info = NULL; + return NS_ERROR_FAILURE; + } + PR_ASSERT(record->entry != NULL); + + // Is there already an II obj associated with the interface_record? + if (record->info != NULL) { + // yay! + *info = record->info; + NS_ADDREF(*info); + return NS_OK; + } + + // nope, better make one. first, find a parent for it. + nsIInterfaceInfo *parent; + XPTInterfaceDirectoryEntry *entry = record->entry; + uint16 parent_index = entry->interface_descriptor->parent_interface; + // Does it _get_ a parent? (is it nsISupports?) + if (parent_index == 0) { + // presumably this is only the case for nsISupports. + parent = NULL; + } else { + // there's a parent index that points to an entry in the same table + // that this one was defined in. Accounting for magic offset. + XPTInterfaceDirectoryEntry *parent_entry = + record->which_header->interface_directory + parent_index - 1; + // get a name from it (which should never be null) and build + // that. XXX OPT Hm, could have a helper function to avoid + // second lookup if this entry happens to be resolved. + nsresult nsr = GetInfoForName(parent_entry->name, &parent); + if (NS_IS_ERROR(nsr)) { + *info = NULL; + return NS_ERROR_FAILURE; } } - *info = NULL; - return NS_ERROR_FAILURE; + + // got a parent for it, now build the object itself + nsInterfaceInfo *result = + new nsInterfaceInfo(entry, (nsInterfaceInfo *)parent); + *info = result; + NS_ADDREF(*info); + return NS_OK; } NS_IMETHODIMP nsInterfaceInfoManager::GetIIDForName(const char* name, nsIID** iid) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (!strcmp(name, entry->name)) { - nsIID* p; - - - if(!(p = (nsIID*)mAllocator->Alloc(sizeof(nsIID)))) - break; - - // XXX I'm confused here about the lifetime of IID pointers. - memcpy(p, &entry->iid, sizeof(nsIID)); - *iid = p; - return NS_OK; - } + interface_record *record = + (interface_record *)PL_HashTableLookup(this->mInterfaceTable, name); + if (record == NULL || record->resolved == PR_FALSE) { + *iid = NULL; + return NS_ERROR_FAILURE; } - *iid = NULL; - return NS_ERROR_FAILURE; + PR_ASSERT(record->entry != NULL); + + nsIID* p; + if(!(p = (nsIID *)mAllocator->Alloc(sizeof(nsIID)))) + return NS_ERROR_FAILURE; + + // XXX I'm confused here about the lifetime of IID pointers. + memcpy(p, &record->entry->iid, sizeof(nsIID)); + *iid = p; + return NS_OK; } NS_IMETHODIMP nsInterfaceInfoManager::GetNameForIID(const nsIID* iid, char** name) { - for(int i = 0; i < mHeader->num_interfaces; i++) { - XPTInterfaceDirectoryEntry *entry = &mHeader->interface_directory[i]; - if (iid->Equals(entry->iid)) { - char* p; - int len = strlen(entry->name)+1; - if(!(p = (char*)mAllocator->Alloc(len))) - break; - memcpy(p, &entry->name, len); - *name = p; - return NS_OK; - } + nsIDKey idKey(*iid); + char *result_name = (char *)this->mIIDTable->Get(&idKey); + +#ifdef DEBUG + // XXX assert here that lookup in table matches iid? + nsIID *newid; + nsresult isok = GetIIDForName(result_name, &newid); + PR_ASSERT(newid->Equals(*newid)); + PR_ASSERT(isok == NS_OK); +#endif + + if (result_name == NULL) { + *name = NULL; + return NS_ERROR_FAILURE; } - *name = NULL; - return NS_ERROR_FAILURE; -} + + char *p; + int len = strlen(result_name) + 1; + if(!(p = (char *)mAllocator->Alloc(len))) { + *name = NULL; + return NS_ERROR_FAILURE; + } + memcpy(p, result_name, len); + *name = p; + return NS_OK; +} // XXX this goes away; IIM should be a service. // ... where does decl for this go? @@ -272,3 +480,35 @@ XPTI_GetInterfaceInfoManager() { return nsInterfaceInfoManager::GetInterfaceInfoManager(); } + +#if 0 +struct XPTInterfaceDirectoryEntry { + nsID iid; + char *name; + char *name_space; + XPTInterfaceDescriptor *interface_descriptor; +#if 0 /* not yet */ + /* not stored on disk */ + uint32 offset; /* the offset for an ID still to be read */ +#endif +}; + +struct XPTInterfaceDescriptor { + uint16 parent_interface; + uint16 num_methods; + XPTMethodDescriptor *method_descriptors; + uint16 num_constants; + XPTConstDescriptor *const_descriptors; +}; + +struct XPTHeader { + char magic[16]; + uint8 major_version; + uint8 minor_version; + uint16 num_interfaces; + uint32 file_length; + XPTInterfaceDirectoryEntry *interface_directory; + uint32 data_pool; + XPTAnnotation *annotations; +}; +#endif diff --git a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.h b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.h index 63c30f4c48f..4703e819513 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.h +++ b/mozilla/xpcom/reflect/xptinfo/src/nsInterfaceInfoManager.h @@ -28,6 +28,12 @@ #include "nsInterfaceInfo.h" +#include "nsHashtable.h" + +#include "plhash.h" + +class hash_record; + class nsInterfaceInfoManager : public nsIInterfaceInfoManager { NS_DECL_ISUPPORTS; @@ -48,13 +54,37 @@ public: static nsIAllocator* GetAllocator(nsInterfaceInfoManager* iim = NULL); private: - // temporary hack - nsInterfaceInfo **mInfoArray; - nsInterfaceInfo *buildII(XPTInterfaceDirectoryEntry *entry); + friend nsIInterfaceInfo* + nsXPTParamInfo::GetInterface(XPTInterfaceDirectoryEntry *entry) const; + friend const nsIID* + nsXPTParamInfo::GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const; + + void initInterfaceTables(); + + // mapping between names and records + PLHashTable *mInterfaceTable; + + // mapping between entries and typelibs (for nsXPTParamInfo::GetInterface) + PLHashTable *mTypelibTable; + + // mapping between iids and names + // (record handling is looked up by name; iids are translated there) + nsHashtable *mIIDTable; - XPTHeader *mHeader; nsInterfaceInfo *mParent; nsIAllocator* mAllocator; }; +// For references in the mInterfaceTable hashtable. +class interface_record { +public: + XPTHeader *which_header; + PRBool resolved; + int which; + XPTInterfaceDirectoryEntry *entry; + nsInterfaceInfo *info; +}; + + + #endif /* nsInterfaceInfoManager_h___ */ diff --git a/mozilla/xpcom/reflect/xptinfo/src/nsXPTParamInfo.cpp b/mozilla/xpcom/reflect/xptinfo/src/nsXPTParamInfo.cpp index 8c5d90165e7..61bdd6e2c82 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/nsXPTParamInfo.cpp +++ b/mozilla/xpcom/reflect/xptinfo/src/nsXPTParamInfo.cpp @@ -16,8 +16,10 @@ * Reserved. */ -// Convienence bits of nsXPTParamInfo that don't fit into xpt_cpp.h -// flyweight wrappers. +/* + * Convienence bits of nsXPTParamInfo that don't fit into xpt_cpp.h + * flyweight wrappers. + */ #include "nsISupports.h" #include "nsIInterfaceInfoManager.h" @@ -31,26 +33,67 @@ // Placeholder - this implementation just returns NULL. nsIInterfaceInfo* -nsXPTParamInfo::GetInterface() const +nsXPTParamInfo::GetInterface(XPTInterfaceDirectoryEntry *entry) const { - NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE,"not an interface"); + NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE, + "not an interface"); nsIInterfaceInfoManager* mgr; if(!(mgr = nsInterfaceInfoManager::GetInterfaceInfoManager())) return NULL; + nsInterfaceInfoManager* mymgr = (nsInterfaceInfoManager *)mgr; -// nsIInterfaceInfo* info; -// mgr->GetInfoForIID(&InterfaceDirectoryEntryTable[type.type.interface].iid, -// &info); - NS_RELEASE(mgr); -// return info; - return NULL; + // what typelib did the entry come from? + XPTHeader *which_header = + (XPTHeader *)PL_HashTableLookup(mymgr->mTypelibTable, entry); + NS_ASSERTION(which_header != NULL, ""); + + // can't use IID, because it could be null for this entry. + char *interface_name; + interface_name = which_header->interface_directory[type.type.interface].name; + + nsIInterfaceInfo *info; + nsresult nsr = mymgr->GetInfoForName(interface_name, &info); + if (NS_IS_ERROR(nsr)) { + NS_RELEASE(mgr); + return NULL; + } + return info; } const nsIID* -nsXPTParamInfo::GetInterfaceIID() const +nsXPTParamInfo::GetInterfaceIID(XPTInterfaceDirectoryEntry *entry) const { - NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE,"not an interface"); -// return &InterfaceDirectoryEntryTable[type.type.interface].iid; - return (const nsIID*) NULL; + NS_PRECONDITION(GetType().TagPart() == nsXPTType::T_INTERFACE, + "not an interface"); + + nsIInterfaceInfoManager* mgr; + if(!(mgr = nsInterfaceInfoManager::GetInterfaceInfoManager())) + return NULL; + nsInterfaceInfoManager* mymgr = (nsInterfaceInfoManager *)mgr; + + // what typelib did the entry come from? + XPTHeader *which_header = + (XPTHeader *)PL_HashTableLookup(mymgr->mTypelibTable, entry); + NS_ASSERTION(which_header != NULL, ""); + + // can't use IID, because it could be null for this entry. + char *interface_name; + interface_name = which_header->interface_directory[type.type.interface].name; + + nsIID* iid; + + nsresult nsr = mymgr->GetIIDForName(interface_name, &iid); + if (NS_IS_ERROR(nsr)) { + NS_RELEASE(mgr); + return NULL; + } + return iid; } + + + + + + + diff --git a/mozilla/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp b/mozilla/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp index 4f6a370a1ce..af7b2be2ab5 100644 --- a/mozilla/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp +++ b/mozilla/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp @@ -25,14 +25,54 @@ #include "nsIInterfaceInfoManager.h" #include "xptinfo.h" +#include + +#include "../src/nsInterfaceInfo.h" + static void RegAllocator(); int main (int argc, char **argv) { RegAllocator(); nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager(); - nsIID *iid; - iim->GetIIDForName("Interface", &iid); + nsIID *iid1, *iid2, *iid3, *iid4; + char *name1, *name2, *name3, *name4; + nsIInterfaceInfo *info1, *info2, *info3, *info4; + + fprintf(stderr, "\ngetting iid for 'Interface'\n"); + iim->GetIIDForName("Interface", &iid1); + iim->GetNameForIID(iid1, &name1); + fprintf(stderr, "%s iid %s\n", name1, iid1->ToString()); + + fprintf(stderr, "\ngetting iid for 'nsIBaseStream'\n"); + iim->GetIIDForName("nsIBaseStream", &iid2); + iim->GetNameForIID(iid2, &name2); + fprintf(stderr, "%s iid %s\n", name2, iid2->ToString()); + + fprintf(stderr, "iid: %s, name: %s\n", iid1->ToString(), name1); + fprintf(stderr, "iid: %s, name: %s\n", iid2->ToString(), name2); + + fprintf(stderr, "\ngetting info for iid2 from above\n"); + iim->GetInfoForIID(iid2, &info2); +#ifdef DEBUG + ((nsInterfaceInfo *)info2)->print(stderr); +#endif + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid3); + iim->GetNameForIID(iid3, &name3); + fprintf(stderr, "%s iid %s\n", name3, iid2->ToString()); + iim->GetInfoForIID(iid3, &info3); +#ifdef DEBUG + ((nsInterfaceInfo *)info3)->print(stderr); +#endif + + fprintf(stderr, "\ngetting info for name 'nsIBidirectionalEnumerator'\n"); + iim->GetInfoForName("nsIBidirectionalEnumerator", &info4); +#ifdef DEBUG + ((nsInterfaceInfo *)info4)->print(stderr); +#endif + return 0; } @@ -59,5 +99,3 @@ static void RegAllocator() nsRepository::RegisterComponent(kAllocatorCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE); } - -