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.
This commit is contained in:
mccabe%netscape.com 1999-03-10 04:26:15 +00:00
Родитель a15117ca9c
Коммит a7a7b4f959
16 изменённых файлов: 1118 добавлений и 376 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <stdio.h>
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

Просмотреть файл

@ -23,6 +23,10 @@
#include "xpt_struct.h"
#include "xpt_cpp.h"
#ifdef DEBUG
#include <stdio.h>
#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___ */

Просмотреть файл

@ -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

Просмотреть файл

@ -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___ */

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -25,14 +25,54 @@
#include "nsIInterfaceInfoManager.h"
#include "xptinfo.h"
#include <stdio.h>
#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);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <stdio.h>
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

Просмотреть файл

@ -23,6 +23,10 @@
#include "xpt_struct.h"
#include "xpt_cpp.h"
#ifdef DEBUG
#include <stdio.h>
#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___ */

Просмотреть файл

@ -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

Просмотреть файл

@ -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___ */

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -25,14 +25,54 @@
#include "nsIInterfaceInfoManager.h"
#include "xptinfo.h"
#include <stdio.h>
#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);
}