diff --git a/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl b/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl new file mode 100644 index 00000000000..5aa5096101d --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* The nsIInterfaceInfo public declaration. */ + + +#include "nsISupports.idl" + +// forward declaration of non-XPCOM types + +[ptr] native nsXPTMethodInfoPtr(nsXPTMethodInfo); +[ptr] native nsXPTConstantPtr(nsXPTConstant); +[ptr] native nsXPTParamInfoPtr(nsXPTParamInfo); + native nsXPTType(nsXPTType); + +%{C++ +class nsXPTMethodInfo; +class nsXPTConstant; +class nsXPTParamInfo; +class nsXPTType; +%} + +/* this is NOT intended to be scriptable */ +[uuid(215DBE04-94A7-11d2-BA58-00805F8A5DD7)] +interface nsIInterfaceInfo : nsISupports +{ + readonly attribute string name; + readonly attribute nsIIDPtr IID; + + PRBool isScriptable(); + + readonly attribute nsIInterfaceInfo parent; + + /** + * These include counts for parent (and all ancestors). + */ + readonly attribute PRUint16 methodCount; + readonly attribute PRUint16 constantCount; + + /** + * These include methods and constants for parent (and all ancestors). + * + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + void getMethodInfo(in PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getMethodInfoForName(in string methodName, out PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getConstant(in PRUint16 index, + [shared, retval] out nsXPTConstantPtr constant); + + + /** + * Get the interface information or iid associated with a param of some + * method in this interface. + */ + + nsIInterfaceInfo getInfoForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + nsIIDPtr getIIDForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + + /** + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + nsXPTType getTypeForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getSizeIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getLengthIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getInterfaceIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); +}; + diff --git a/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl b/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl new file mode 100644 index 00000000000..e5efa8e1dc3 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* The nsIInterfaceInfoManager public declaration. */ + + +#include "nsISupports.idl" +#include "nsIInterfaceInfo.idl" +#include "nsIEnumerator.idl" + +/* this is NOT intended to be scriptable */ +[uuid(8B161900-BE2B-11d2-9831-006008962422)] +interface nsIInterfaceInfoManager : nsISupports +{ + nsIInterfaceInfo getInfoForIID(in nsIIDPtr iid); + nsIInterfaceInfo getInfoForName(in string name); + + nsIIDPtr getIIDForName(in string name); + string getNameForIID(in nsIIDPtr iid); + + nsIEnumerator enumerateInterfaces(); + + void autoRegisterInterfaces(); +}; \ No newline at end of file diff --git a/mozilla/xpcom/reflect/xptinfo/src/remove_after_fixing_mac_project.h b/mozilla/xpcom/reflect/xptinfo/src/remove_after_fixing_mac_project.h new file mode 100644 index 00000000000..69e71c8afee --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/remove_after_fixing_mac_project.h @@ -0,0 +1,30 @@ + +#ifndef NS_DECL_NSIINTERFACEINFO +#define NS_DECL_NSIINTERFACEINFO \ + NS_IMETHOD GetName(char * *aName); \ + NS_IMETHOD GetIID(nsIID * *aIID); \ + NS_IMETHOD IsScriptable(PRBool *_retval); \ + NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent); \ + NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount); \ + NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount); \ + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info); \ + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info); \ + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant); \ + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval); \ + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval); \ + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval); \ + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); \ + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); \ + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval); +#endif + +#ifndef NS_DECL_NSIINTERFACEINFOMANAGER +#define NS_DECL_NSIINTERFACEINFOMANAGER \ + NS_IMETHOD GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval); \ + NS_IMETHOD GetInfoForName(const char *name, nsIInterfaceInfo **_retval); \ + NS_IMETHOD GetIIDForName(const char *name, nsIID * *_retval); \ + NS_IMETHOD GetNameForIID(const nsIID * iid, char **_retval); \ + NS_IMETHOD EnumerateInterfaces(nsIEnumerator **_retval); \ + NS_IMETHOD AutoRegisterInterfaces(void); +#endif + diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiFile.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiFile.cpp new file mode 100644 index 00000000000..a21400e9b8f --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiFile.cpp @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiFile. */ + +#include "xptiprivate.h" + + +xptiFile::xptiFile() + : mSize(), + mDate(), + mName(nsnull), + mGuts(nsnull) +{ + // empty +} + +xptiFile::xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + const char* aName, + xptiWorkingSet* aWorkingSet, + XPTHeader* aHeader /*= nsnull */) + + : mSize(aSize), + mDate(aDate), + mName(aName), + mGuts(nsnull) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); + + if(aHeader) + SetHeader(aHeader); +} + +xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet, + PRBool cloneGuts) + : mSize(r.mSize), + mDate(r.mDate), + mName(nsnull), + mGuts(nsnull) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); + + if(cloneGuts && r.mGuts) + mGuts = r.mGuts->Clone(); +} + +xptiFile::~xptiFile() +{ + if(mGuts) + delete mGuts; +} + +PRBool +xptiFile::SetHeader(XPTHeader* aHeader) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + + mGuts = new xptiTypelibGuts(aHeader); + if(mGuts && !mGuts->IsValid()) + { + delete mGuts; + mGuts = nsnull; + } + return mGuts != nsnull; +} diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp new file mode 100644 index 00000000000..36ff34a9884 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -0,0 +1,594 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiInterfaceInfo. */ + +#include "xptiprivate.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(xptiInterfaceInfo, nsIInterfaceInfo) + +xptiInterfaceInfo::xptiInterfaceInfo(const char* name, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet& aWorkingSet) + : mIID(iid), + mName(nsnull), + mTypelib(typelib) +{ + NS_INIT_REFCNT(); + + int len = PL_strlen(name); + char* ptr = (char*) XPT_MALLOC(aWorkingSet.GetStringArena(), len+2); + if(ptr) + { + mName = &ptr[1]; + memcpy(mName, name, len); + // XXX These are redundant as long as the underlying arena continues + // to zero out all mallocs. But... + mName[-1] = mName[len] = 0; + } +} + +xptiInterfaceInfo::~xptiInterfaceInfo() +{ + if(HasInterfaceRecord()) + delete mInterface; +} + + +PRBool +xptiInterfaceInfo::Resolve(xptiWorkingSet* aWorkingSet) +{ + int resolvedState = GetResolveState(); + + if(resolvedState == FULLY_RESOLVED) + return PR_TRUE; + if(resolvedState == RESOLVE_FAILED) + return PR_FALSE; + + xptiInterfaceInfoManager* mgr = + xptiInterfaceInfoManager::GetInterfaceInfoManager(); + + if(!mgr) + return PR_FALSE; + + if(!aWorkingSet) + { + aWorkingSet = mgr->GetWorkingSet(); + } + + if(resolvedState == NOT_RESOLVED) + { + printf("~ partial resolve of %s\n", mName); + // Make a copy of mTypelib because the underlying memory will change! + xptiTypelib typelib = mTypelib; + + // We expect our PartiallyResolve() to get called before this returns. + if(!mgr->LoadFile(typelib, aWorkingSet)) + { + NS_RELEASE(mgr); + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + // The state was changed by LoadFile to PARTIALLY_RESOLVED, so this + // ...falls through... + } + NS_IF_RELEASE(mgr); + + NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!"); + + printf("+ final resolve of %s\n", mName); + + // Finish out resolution by finding parent and Resolving it so + // we can set the info we get from it. + + PRUint16 parent_index = mInterface->mDescriptor->parent_interface; + + if(parent_index) + { + xptiInterfaceInfo* parent = + aWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetInfoAtNoAddRef(parent_index - 1); + + if(!parent || !parent->EnsureResolved()) + { + xptiTypelib aTypelib = mInterface->mTypelib; + delete mInterface; + mTypelib = aTypelib; + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + + NS_ADDREF(mInterface->mParent = parent); + + mInterface->mMethodBaseIndex = + parent->mInterface->mMethodBaseIndex + + parent->mInterface->mDescriptor->num_methods; + + mInterface->mConstantBaseIndex = + parent->mInterface->mConstantBaseIndex + + parent->mInterface->mDescriptor->num_constants; + + } + SetResolvedState(FULLY_RESOLVED); + return PR_TRUE; +} + +PRBool +xptiInterfaceInfo::PartiallyResolve(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state"); + + xptiInterfaceGuts* iface = + new xptiInterfaceGuts(aDescriptor, mTypelib, aWorkingSet); + + if(!iface) + return PR_FALSE; + + mInterface = iface; + SetResolvedState(PARTIALLY_RESOLVED); + return PR_TRUE; +} + +/***************************************************************************/ + +NS_IMETHODIMP +xptiInterfaceInfo::GetName(char **name) +{ + NS_PRECONDITION(name, "bad param"); + + if(!mName) + return NS_ERROR_UNEXPECTED; + + char* ptr = *name = (char*) nsAllocator::Clone(mName, PL_strlen(mName)+1); + return ptr ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetIID(nsIID **iid) +{ + NS_PRECONDITION(iid, "bad param"); + + nsIID* ptr = *iid = (nsIID*) nsAllocator::Clone(&mIID, sizeof(nsIID)); + return ptr ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +xptiInterfaceInfo::IsScriptable(PRBool* result) +{ + NS_ASSERTION(result, "bad bad caller!"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *result = XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetParent(nsIInterfaceInfo** parent) +{ + NS_PRECONDITION(parent, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + NS_IF_ADDREF(*parent = mInterface->mParent); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetMethodCount(uint16* count) +{ + NS_PRECONDITION(count, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods; + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetConstantCount(uint16* count) +{ + NS_PRECONDITION(count, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants; + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) +{ + NS_PRECONDITION(info, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetMethodInfo(index, info); + + if(index >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ASSERTION(0, "bad param"); + *info = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[index - + mInterface->mMethodBaseIndex]); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetMethodInfoForName(const char* methodName, uint16 *index, + const nsXPTMethodInfo** result) +{ + NS_PRECONDITION(methodName, "bad param"); + NS_PRECONDITION(index, "bad param"); + NS_PRECONDITION(result, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + // This is a slow algorithm, but this is not expected to be called much. + for(uint16 i = mInterface->mMethodBaseIndex; + i < mInterface->mDescriptor->num_methods; + ++i) + { + const nsXPTMethodInfo* info; + info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[i - + mInterface->mMethodBaseIndex]); + *index = i; + *result = info; + return NS_OK; + } + if(mInterface->mParent) + return mInterface->mParent->GetMethodInfoForName(methodName, index, result); + else + return NS_ERROR_INVALID_ARG; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetConstant(uint16 index, const nsXPTConstant** constant) +{ + NS_PRECONDITION(constant, "bad param"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mConstantBaseIndex) + return mInterface->mParent->GetConstant(index, constant); + + if(index >= mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants) + { + NS_PRECONDITION(0, "bad param"); + *constant = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *constant = + NS_REINTERPRET_CAST(nsXPTConstant*, + &mInterface->mDescriptor-> + const_descriptors[index - + mInterface->mConstantBaseIndex]); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetInfoForParam(uint16 methodIndex, + const nsXPTParamInfo *param, + nsIInterfaceInfo** info) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(info, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetInfoForParam(methodIndex, param, info); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_PRECONDITION(0, "bad param"); + *info = NULL; + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor-> + additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) { + NS_ASSERTION(0, "not an interface"); + return NS_ERROR_INVALID_ARG; + } + + nsIInterfaceInfo* theInfo = + mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetInfoAtNoAddRef(td->type.interface - 1); + + NS_IF_ADDREF(*info = theInfo); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetIIDForParam(uint16 methodIndex, + const nsXPTParamInfo* param, nsIID** iid) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(iid, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetIIDForParam(methodIndex, param, iid); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_PRECONDITION(0, "bad param"); + *iid = NULL; + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor-> + additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) { + NS_ASSERTION(0, "not an interface"); + return NS_ERROR_INVALID_ARG; + } + + nsIInterfaceInfo* theInfo = + mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetInfoAtNoAddRef(td->type.interface - 1); + + return theInfo->GetIID(iid); +} + +// this is a private helper +NS_IMETHODIMP +xptiInterfaceInfo::GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type) +{ + NS_ASSERTION(param, "bad state"); + NS_ASSERTION(type, "bad state"); + NS_ASSERTION(IsFullyResolved(), "bad state"); + + const XPTTypeDescriptor *td = ¶m->type; + const XPTTypeDescriptor *additional_types = + mInterface->mDescriptor->additional_types; + + for (uint16 i = 0; i < dimension; i++) { + if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) { + NS_ASSERTION(0, "bad dimension"); + return NS_ERROR_INVALID_ARG; + } + td = &additional_types[td->type.additional_type]; + } + + *type = td; + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetTypeForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + nsXPTType* type) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(type, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetTypeForParam(methodIndex, param, + dimension, type); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ASSERTION(0, "bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + *type = nsXPTType(td->prefix); + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetSizeIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(argnum, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetSizeIsArgNumberForParam(methodIndex, param, + dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ASSERTION(0, "bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + // verify that this is a type that has size_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ASSERTION(0, "not a size_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetLengthIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(argnum, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetLengthIsArgNumberForParam(methodIndex, param, + dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ASSERTION(0, "bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) { + return rv; + } + } + else + td = ¶m->type; + + // verify that this is a type that has length_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ASSERTION(0, "not a length_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum2; + return NS_OK; +} + +NS_IMETHODIMP +xptiInterfaceInfo::GetInterfaceIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint8* argnum) +{ + NS_PRECONDITION(param, "bad pointer"); + NS_PRECONDITION(argnum, "bad pointer"); + + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetInterfaceIsArgNumberForParam(methodIndex, param, + argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ASSERTION(0, "bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor-> + additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) { + NS_ASSERTION(0, "not an iid_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp new file mode 100644 index 00000000000..1a1faaa92c6 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -0,0 +1,1208 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiInterfaceInfoManager. */ + +#include "xptiprivate.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(xptiInterfaceInfoManager, nsIInterfaceInfoManager) + +static xptiInterfaceInfoManager* gInterfaceInfoManager = nsnull; + +// static +xptiInterfaceInfoManager* +xptiInterfaceInfoManager::GetInterfaceInfoManager() +{ + if(!gInterfaceInfoManager) + { + gInterfaceInfoManager = new xptiInterfaceInfoManager(); + if(gInterfaceInfoManager) + NS_ADDREF(gInterfaceInfoManager); + if(!gInterfaceInfoManager->mWorkingSet.IsValid()) + NS_RELEASE(gInterfaceInfoManager); + } + if(gInterfaceInfoManager) + NS_ADDREF(gInterfaceInfoManager); + return gInterfaceInfoManager; +} + +void +xptiInterfaceInfoManager::FreeInterfaceInfoManager() +{ + NS_IF_RELEASE(gInterfaceInfoManager); +} + +xptiInterfaceInfoManager::xptiInterfaceInfoManager() + : mWorkingSet() +{ + NS_INIT_ISUPPORTS(); + if(!xptiManifest::Read(this, mWorkingSet)) + AutoRegisterInterfaces(); +} + +xptiInterfaceInfoManager::~xptiInterfaceInfoManager() +{ + // We only do this on shutdown of the service. + mWorkingSet.InvalidateInterfaceInfos(); +} + +PRBool +xptiInterfaceInfoManager::GetComponentsDir(nsILocalFile** aDir) +{ + NS_ASSERTION(aDir,"loser!"); + + // Make a new one each time because caller *will* modify it. + + nsCOMPtr dir = do_CreateInstance(NS_LOCAL_FILE_PROGID); + if(!dir) + return PR_FALSE; + + nsresult rv = dir->InitWithPath( + nsSpecialSystemDirectory( + nsSpecialSystemDirectory::XPCOM_CurrentProcessComponentDirectory)); + if(NS_FAILED(rv)) + return PR_FALSE; + + NS_ADDREF(*aDir = dir); + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::BuildFileList(nsISupportsArray** aFileList) +{ + NS_ASSERTION(aFileList, "loser!"); + + nsresult rv; + + nsCOMPtr dir; + + rv = GetComponentsDir(getter_AddRefs(dir)); + if(NS_FAILED(rv) || !dir) + return PR_FALSE; + + nsCOMPtr entries; + rv = dir->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + return PR_FALSE; + + nsCOMPtr fileList = + do_CreateInstance(NS_SUPPORTSARRAY_PROGID); + if(!fileList) + return PR_FALSE; + + PRUint32 count = 0; + PRBool hasMore; + while(NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr sup; + entries->GetNext(getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + char* name; + if(NS_FAILED(file->GetLeafName(&name))) + return PR_FALSE; + + int flen = PL_strlen(name); + if (flen < 4 || + (PL_strcasecmp(&(name[flen - 4]), ".xpt")) && + (PL_strcasecmp(&(name[flen - 4]), ".zip")) && + (PL_strcasecmp(&(name[flen - 4]), ".jar"))) { + nsAllocator::Free(name); + continue; + } + nsAllocator::Free(name); + + PRBool isFile; + if(NS_FAILED(file->IsFile(&isFile)) || !isFile) + { + nsAllocator::Free(name); + continue; + } + + if(!fileList->InsertElementAt(file, count)) + return PR_FALSE; + ++count; + } + + NS_ADDREF(*aFileList = fileList); + return PR_TRUE; +} + + +xptiInterfaceInfoManager::AutoRegMode +xptiInterfaceInfoManager::DetermineAutoRegStrategy(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet) +{ + // XXX implement! + return FULL_VALIDATION_REQUIRED; +} + +#if 0 +PRBool +xptiInterfaceInfoManager::PopulateFileRecordsInWorkingSet(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet) +{ + // XXX implement + return PR_FALSE; +} +#endif + +PRBool +xptiInterfaceInfoManager::AttemptAddOnlyFromFileList(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet, + AutoRegMode* pmode) +{ + // XXX implement + + return PR_TRUE; +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFile(nsILocalFile* aFile, + xptiWorkingSet& aWorkingSet) +{ + NS_ASSERTION(aFile, "loser!"); + + XPTHeader *header = nsnull; + char *whole = nsnull; + FILE* file = nsnull; + XPTState *state = nsnull; + XPTCursor cursor; + PRUint32 flen; + PRInt64 fileSize; + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + { + return nsnull; + } + + whole = new char[flen]; + if (!whole) + { + return nsnull; + } + + // all exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenANSIFileDesc("rb", &file)) || !file) + { + goto out; + } + + if(flen > fread(whole, 1, flen, file)) + { + goto out; + } + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet.GetStructArena(), &cursor, &header)) + { + goto out; + } + + out: + if(file) + fclose(file); + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + return header; +} + +PRBool +xptiInterfaceInfoManager::LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet) +{ + if(!aWorkingSet) + aWorkingSet = &mWorkingSet; + + if(!aWorkingSet->IsValid()) + return PR_FALSE; + + xptiFile* fileRecord = &aWorkingSet->GetFileAt(aTypelibRecord.GetFileIndex()); + xptiZipItem* zipItem = nsnull; + + nsCOMPtr file; + if(!GetComponentsDir(getter_AddRefs(file)) || !file) + return PR_FALSE; + + if(NS_FAILED(file->Append(fileRecord->GetName()))) + return PR_FALSE; + + XPTHeader* header; + + if(aTypelibRecord.IsZip()) + { + zipItem = &aWorkingSet->GetZipItemAt(aTypelibRecord.GetZipItemIndex()); + printf("# loading zip item %s::%s\n", fileRecord->GetName(), zipItem->GetName()); + header = ReadXPTFileFromZip(file, zipItem->GetName(), *aWorkingSet); + } + else + { + printf("^ loading file %s\n", fileRecord->GetName()); + header = ReadXPTFile(file, *aWorkingSet); + } + + if(!header) + return PR_FALSE; + + + if(aTypelibRecord.IsZip()) + { + // This also allocs zipItem.GetGuts() used below. + if(!zipItem->SetHeader(header)) + return PR_FALSE; + } + else + { + // This also allocs fileRecord.GetGuts() used below. + if(!fileRecord->SetHeader(header)) + return PR_FALSE; + } + + // For each interface in the header we want to find the xptiInterfaceInfo + // object and set its resolution info. + + for(PRUint16 i = 0; i < header->num_interfaces; i++) + { + static const nsID zeroIID = + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }; + + XPTInterfaceDirectoryEntry* iface = header->interface_directory + i; + xptiInterfaceInfo* info; + + if(!iface->iid.Equals(zeroIID)) + { + info = (xptiInterfaceInfo*) + PL_HashTableLookup(aWorkingSet->mIIDTable, &iface->iid); + } + else + { + info = (xptiInterfaceInfo*) + PL_HashTableLookup(aWorkingSet->mNameTable, iface->name); + } + + if(!info) + { + // This one is just not resolved anywhere! + continue; + } + + if(aTypelibRecord.IsZip()) + zipItem->GetGuts()->SetInfoAt(i, info); + else + fileRecord->GetGuts()->SetInfoAt(i, info); + + XPTInterfaceDescriptor* descriptor = iface->interface_descriptor; + + if(descriptor && aTypelibRecord.Equals(info->GetTypelibRecord())) + info->PartiallyResolve(descriptor, aWorkingSet); + } + return PR_TRUE; +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFileFromZip(nsILocalFile* file, + const char* itemName, + xptiWorkingSet& aWorkingSet) +{ + nsCOMPtr zip = + do_CreateInstance("component://netscape/libjar"); + if(!zip) + { + return nsnull; + } + + if(NS_FAILED(zip->Init(file)) || NS_FAILED(zip->Open())) + { + return nsnull; + } + + // This is required before getting streams for some reason. + if(NS_FAILED(zip->ParseManifest())) + { + return nsnull; + } + + nsCOMPtr entry; + if(NS_FAILED(zip->GetEntry(itemName, getter_AddRefs(entry))) || !entry) + { + return nsnull; + } + + return ReadXPTFileFromOpenZip(zip, entry, itemName, aWorkingSet); +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFileFromOpenZip(nsIZipReader* zip, + nsIZipEntry* entry, + const char* itemName, + xptiWorkingSet& aWorkingSet) +{ + NS_ASSERTION(zip, "loser!"); + NS_ASSERTION(entry, "loser!"); + NS_ASSERTION(itemName, "loser!"); + + + XPTHeader *header = nsnull; + char *whole = nsnull; + XPTState *state = nsnull; + XPTCursor cursor; + PRUint32 flen; + PRUint32 totalRead = 0; + + if(NS_FAILED(entry->GetRealSize(&flen)) || !flen) + { + return nsnull; + } + + nsCOMPtr stream; + if(NS_FAILED(zip->GetInputStream(itemName, getter_AddRefs(stream))) || !stream) + { + return nsnull; + } + + whole = new char[flen]; + if (!whole) + { + return nsnull; + } + + // all exits from on here should be via 'goto out' + + while(flen - totalRead) + { + PRUint32 avail; + PRUint32 read; + + if(NS_FAILED(stream->Available(&avail))) + { + goto out; + } + + if(avail > flen) + { + goto out; + } + + if(NS_FAILED(stream->Read(whole+totalRead, avail, &read))) + { + goto out; + } + + totalRead += read; + } + + // Go ahead and close the stream now. + stream = nsnull; + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet.GetStructArena(), &cursor, &header)) + { + goto out; + } + + out: + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + return header; +} + +static PRBool +IsXPTFile(const char* name) +{ + NS_ASSERTION(name, "bad name"); + NS_ASSERTION(PL_strlen(name) >= 4, "bad name"); + return 0 == PL_strcasecmp(&(name[PL_strlen(name) - 4]), ".xpt"); +} + +static int +IndexOfFileWithName(const char* aName, const xptiWorkingSet& aWorkingSet) +{ + NS_ASSERTION(aName, "loser!"); + + for(PRUint32 i = 0; i < aWorkingSet.GetFileCount(); ++i) + { + if(!PL_strcmp(aName, aWorkingSet.GetFileAt(i).GetName())) + return i; + } + return -1; +} + +static PR_CALLBACK int +xptiSortFileList(const void * p1, const void *p2, void * closure) +{ + nsILocalFile* pFile1 = *((nsILocalFile**) p1); + nsILocalFile* pFile2 = *((nsILocalFile**) p2); + xptiWorkingSet* pWorkingSet = (xptiWorkingSet*) closure; + + char* name1; + char* name2; + + if(NS_FAILED(pFile1->GetLeafName(&name1))) + { + NS_ASSERTION(0, "way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetLeafName(&name2))) + { + NS_ASSERTION(0, "way bad, with no happy out!"); + return 0; + } + + int index1 = IndexOfFileWithName(name1, *pWorkingSet); + int index2 = IndexOfFileWithName(name2, *pWorkingSet); + + // Get thses now in case we need them later. + PRBool isXPT1 = IsXPTFile(name1); + PRBool isXPT2 = IsXPTFile(name2); + int nameOrder = PL_strcmp(name1, name2); + + nsAllocator::Free(name1); + nsAllocator::Free(name2); + + // XXX need to test with non-empty working sets to be sure this right + + // both in workingSet, preserve old order + if(index1 != -1 && index2 != -1) + return index1 - index2; + + if(index1 != -1) + return 1; + + if(index2 != -1) + return -1; + + // .xpt files come before archives (.zip, .jar, etc) + if(isXPT1 &&!isXPT2) + return -1; + + if(!isXPT1 && isXPT2) + return 1; + + // neither element is in the workingSet and both are same type, sort by size + + PRInt64 size1; + PRInt64 size2; + + if(NS_FAILED(pFile1->GetFileSize(&size1))) + { + NS_ASSERTION(0, "way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetFileSize(&size2))) + { + NS_ASSERTION(0, "way bad, with no happy out!"); + return 0; + } + + // by size with largest first, or by name if size is the same + int sizeDiff = int(PRInt32(nsInt64(size2) - nsInt64(size1))); + return sizeDiff != 0 ? sizeDiff : nameOrder; +} + +PRBool +xptiInterfaceInfoManager::DoFullValidationMergeFromFileList(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet) +{ + // nsresult rv; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + + if(!aWorkingSet.IsValid()) + return PR_FALSE; + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + + if(!countOfFilesInFileList) + { + // XXX do the right thing here! + return PR_FALSE; + } + + // We want to end up with a file list that starts with the files from + // aWorkingSet (but only those that are in aFileList) in the order in + // which they appeared in aWorkingSet. Following those files will be those + // files in aFileList which are not in aWorkingSet. These additional + // files will be ordered by file size (larger first) but all .xpt files + // will preceed all zipfile of those files not already in the working set. + // To do this we will do a fancy sort on a copy of aFileList. + + + nsILocalFile** orderedFileList = (nsILocalFile**) + XPT_MALLOC(aWorkingSet.GetStructArena(), + sizeof(nsILocalFile*) * countOfFilesInFileList); + + // fill our list for sorting + for(i = 0; i < countOfFilesInFileList; ++i) + { + nsCOMPtr sup; + aFileList->GetElementAt(i, getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + // Intentionally NOT addref'd cuz we know these are pinned in aFileList. + orderedFileList[i] = file.get(); + } + + // sort the filelist + NS_QuickSort(orderedFileList, countOfFilesInFileList, sizeof(nsILocalFile*), + xptiSortFileList, &aWorkingSet); + + + // dump the sorted list + for(i = 0; i < countOfFilesInFileList; ++i) + { + nsILocalFile* file = orderedFileList[i]; + + char* name; + if(NS_FAILED(file->GetLeafName(&name))) + return PR_FALSE; + + printf("* found %s\n", name); + nsAllocator::Free(name); + } + + + // Make space in aWorkingset for a new xptiFile array. + + if(!aWorkingSet.NewFileArray(countOfFilesInFileList)) + return PR_FALSE; + + aWorkingSet.ClearHashTables(); + + // For each file, add any valid interfaces that don't conflict with + // previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileList[i]; + + char* name; + PRInt64 size; + PRInt64 date; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModificationDate(&date)) || + NS_FAILED(file->GetLeafName(&name))) + { + return PR_FALSE; + } + + xptiFile fileRecord(nsInt64(size), nsInt64(date), name, &aWorkingSet); + nsAllocator::Free(name); + +// printf("* found %s\n", fileRecord.GetName()); + + + if(IsXPTFile(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ASSERTION(0,""); + continue; + } + + if(!header->num_interfaces) + { + // We are not interested in files without interfaces. + continue; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet.GetFileCount()); + + int countOfInterfacesAddedForFile = 0; + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceInfo* info = nsnull; + + if(!VerifyAndAddInterfaceIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &info)) + return PR_FALSE; + + if(!info) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!countOfInterfacesAddedForFile) + { + if(!fileRecord.SetHeader(header)) + { + // XXX that would be bad. + return PR_FALSE; + } + } + fileRecord.GetGuts()->SetInfoAt(k, info); + ++countOfInterfacesAddedForFile; + } + + if(countOfInterfacesAddedForFile) + { + // This will correspond to typelibRecord above. + aWorkingSet.AppendFile(fileRecord); + } + } + else // It is a zip file, Oh boy! + { + nsCOMPtr zip = + do_CreateInstance("component://netscape/libjar"); + if(!zip) + return PR_FALSE; + if(NS_FAILED(zip->Init(file)) || NS_FAILED(zip->Open())) + return PR_FALSE; + + // This is required before getting streams for some reason. + if(NS_FAILED(zip->ParseManifest())) + return PR_FALSE; + + nsCOMPtr entries; + if(NS_FAILED(zip->FindEntries("*.xpt", getter_AddRefs(entries))) || + !entries) + { + // XXX We TRUST that this means there are no .xpt files. + continue; + } + + int countOfInterfacesAddedForFile = 0; + + do + { + // For each item... + int countOfInterfacesAddedForItem = 0; + + PRBool hasMore; + if(NS_FAILED(entries->HasMoreElements(&hasMore))) + return PR_FALSE; + if(!hasMore) + break; + + nsCOMPtr sup; + if(NS_FAILED(entries->GetNext(getter_AddRefs(sup))) ||!sup) + return PR_FALSE; + + nsCOMPtr entry = do_QueryInterface(sup); + if(!entry) + return PR_FALSE; + + // we have a zip entry! + + char* itemName = nsnull; + + if(NS_FAILED(entry->GetName(&itemName)) || !itemName) + return PR_FALSE; + + + xptiZipItem zipItemRecord(itemName, &aWorkingSet); + XPTHeader* header = + ReadXPTFileFromOpenZip(zip, entry, itemName, aWorkingSet); + nsAllocator::Free(itemName); + + if(!header) + { + // XXX do something! + NS_ASSERTION(0,""); + continue; + } + + if(!header->num_interfaces) + { + // We are not interested in files without interfaces. + continue; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet.GetFileCount(), + aWorkingSet.GetZipItemCount()); + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceInfo* info = nsnull; + + if(!VerifyAndAddInterfaceIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &info)) + return PR_FALSE; + + if(!info) + continue; + + // If this is the first interface we found for this item + // then setup the zipItemRecord for the header and infos. + if(!countOfInterfacesAddedForItem) + { + // XXX fix this! + if(!zipItemRecord.SetHeader(header)) + { + // XXX that would be bad. + return PR_FALSE; + } + } + + // zipItemRecord.GetGuts()->SetInfoAt(k, info); + ++countOfInterfacesAddedForItem; + ++countOfInterfacesAddedForFile; + } + + if(countOfInterfacesAddedForItem) + { + if(!aWorkingSet.GetZipItemFreeSpace()) + { + if(!aWorkingSet.ExtendZipItemArray( + aWorkingSet.GetZipItemCount() + 20)) + { + // out of space! + return PR_FALSE; + } + } + aWorkingSet.AppendZipItem(zipItemRecord); + } + } while(1); + + if(countOfInterfacesAddedForFile) + { + // This will correspond to typelibRecord above. + aWorkingSet.AppendFile(fileRecord); + } + } + } + return PR_TRUE; +} +PRBool +xptiInterfaceInfoManager::VerifyAndAddInterfaceIfNew(xptiWorkingSet& aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceInfo** infoAdded) +{ + NS_ASSERTION(iface, "loser!"); + NS_ASSERTION(infoAdded, "loser!"); + + *infoAdded = nsnull; + + if(!iface->interface_descriptor) + { + // Not resolved, ignore this one. + // XXX full logging might note this... + return PR_TRUE; + } + + xptiInterfaceInfo* info = (xptiInterfaceInfo*) + PL_HashTableLookup(aWorkingSet.mIIDTable, &iface->iid); + + if(info) + { + // XXX validate this info to find possible inconsistencies + return PR_TRUE; + } + + // Build a new xptiInterfaceInfo object and hook it up. + + info = new xptiInterfaceInfo(iface->name, iface->iid, + typelibRecord, aWorkingSet); + if(!info) + { + // XXX bad! + return PR_FALSE; + } + + NS_ADDREF(info); + if(!info->IsValid()) + { + // XXX bad! + NS_RELEASE(info); + return PR_FALSE; + } + + // The name table now owns the reference we AddRef'd above + PL_HashTableAdd(aWorkingSet.mNameTable, iface->name, info); + PL_HashTableAdd(aWorkingSet.mIIDTable, &iface->iid, info); + + *infoAdded = info; + return PR_TRUE; +} + +static PR_CALLBACK PRIntn +xpti_Merger(PLHashEntry *he, PRIntn i, void *arg) +{ + xptiInterfaceInfo* srcInfo = (xptiInterfaceInfo*) he->value; + xptiWorkingSet* aWorkingSet = (xptiWorkingSet*) arg; + + xptiInterfaceInfo* destInfo = (xptiInterfaceInfo*) + PL_HashTableLookup(aWorkingSet->mIIDTable, srcInfo->GetTheIID()); + + if(destInfo) + { + // XXX we could do some serious validation here! + } + else + { + // Clone the xptiInterfaceInfo into our WorkingSet. + + uint16 srcIndex = srcInfo->GetTypelibRecord().GetFileIndex(); + + xptiTypelib typelibRecord; + typelibRecord.Init(srcIndex + aWorkingSet->mMergeOffsetMap[srcIndex]); + + destInfo = new xptiInterfaceInfo(srcInfo->GetTheName(), + *srcInfo->GetTheIID(), + typelibRecord, *aWorkingSet); + + if(!destInfo) + { + // XXX bad! should log + return HT_ENUMERATE_NEXT; + } + + NS_ADDREF(destInfo); + if(!destInfo->IsValid()) + { + // XXX bad! should log + NS_RELEASE(destInfo); + return HT_ENUMERATE_NEXT; + } + + // The name table now owns the reference we AddRef'd above + PL_HashTableAdd(aWorkingSet->mNameTable, destInfo->GetTheName(), destInfo); + PL_HashTableAdd(aWorkingSet->mIIDTable, destInfo->GetTheIID(), destInfo); + } + + return HT_ENUMERATE_NEXT; +} + + +PRBool +xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet& aDestWorkingSet, + xptiWorkingSet& aSrcWorkingSet) +{ + // Combine file lists. + + PRUint32 originalTypelibFileCount = aDestWorkingSet.GetFileCount(); + PRUint32 additionalTypelibFileCount = aSrcWorkingSet.GetFileCount(); + PRUint32 i; + + if(!additionalTypelibFileCount) + return PR_TRUE; + + // Create a new array big enough to hold both lists and copy existing files + + if(!aDestWorkingSet.ExtendFileArray(originalTypelibFileCount + + additionalTypelibFileCount)) + return PR_FALSE; + + // Now we are where we started, but we know we have enough space. + + // Prepare offset array for later fixups. + // NOTE: Storing with dest, but alloc'ing from src. This is intentional. + aDestWorkingSet.mMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet.GetStructArena(), + additionalTypelibFileCount * sizeof(PRUint32)); + + for(i = 0; i < additionalTypelibFileCount; ++i) + { + xptiFile& srcFile = aSrcWorkingSet.GetFileAt(i); + PRUint32 k; + for(k = 0; k < originalTypelibFileCount; ++k) + { + // If file (with same name, date, and time) is in both lists + // then reuse that record. + xptiFile& destFile = aDestWorkingSet.GetFileAt(k); + if(srcFile.Equals(destFile)) + { + aDestWorkingSet.mMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalTypelibFileCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet.GetFileCount(); + + aDestWorkingSet.AppendFile( + xptiFile(srcFile, &aDestWorkingSet, PR_FALSE)); + + // Fixup the merge offset map. + aDestWorkingSet.mMergeOffsetMap[i] = newIndex - i; + } + } + + // Now the dest file array is set up, migrate xptiInterfaceInfos + + PL_HashTableEnumerateEntries(aSrcWorkingSet.mNameTable, xpti_Merger, + &aDestWorkingSet); + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileList(nsISupportsArray* aFileList) +{ + PRUint32 count; + + if(NS_FAILED(aFileList->Count(&count))) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr sup; + aFileList->GetElementAt(i, getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + char* name; + if(NS_FAILED(file->GetLeafName(&name))) + return PR_FALSE; + + printf("* found %s\n", name); + nsAllocator::Free(name); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileListInWorkingSet(xptiWorkingSet& aWorkingSet) +{ + for(PRUint16 i = 0; i < aWorkingSet.GetFileCount(); ++i) + { + xptiFile& record = aWorkingSet.GetFileAt(i); + + printf("! has %s\n", record.GetName()); + } + return PR_TRUE; +} + + +/***************************************************************************/ + +/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiInterfaceInfo* info = (xptiInterfaceInfo*) + PL_HashTableLookup(mWorkingSet.mIIDTable, iid); + + if(!info) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + NS_ADDREF(*_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info)); + return NS_OK; +} + +/* nsIInterfaceInfo getInfoForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiInterfaceInfo* info = (xptiInterfaceInfo*) + PL_HashTableLookup(mWorkingSet.mNameTable, name); + + if(!info) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + NS_ADDREF(*_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info)); + return NS_OK; +} + +/* nsIIDPtr getIIDForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiInterfaceInfo* info = (xptiInterfaceInfo*) + PL_HashTableLookup(mWorkingSet.mNameTable, name); + + if(!info) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return info->GetIID(_retval); +} + +/* string getNameForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiInterfaceInfo* info = (xptiInterfaceInfo*) + PL_HashTableLookup(mWorkingSet.mIIDTable, iid); + + if(!info) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return info->GetName(_retval); +} + +static PR_CALLBACK PRIntn +xpti_ArrayAppender(PLHashEntry *he, PRIntn i, void *arg) +{ + nsIInterfaceInfo* ii = (nsIInterfaceInfo*) he->value; + nsISupportsArray* array = (nsISupportsArray*) arg; + + // XXX nsSupportsArray.h shows that this method returns the wrong value! + array->AppendElement(ii); + return HT_ENUMERATE_NEXT; +} + + +/* nsIEnumerator enumerateInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval) +{ + // I didn't want to incur the size overhead of using nsHashtable just to + // make building an enumerator easier. So, this code makes a snapshot of + // the table using an nsISupportsArray and builds an enumerator for that. + // We can afford this transient cost. + + nsCOMPtr array = + do_CreateInstance(NS_SUPPORTSARRAY_PROGID); + if(!array) + return NS_ERROR_UNEXPECTED; + + PL_HashTableEnumerateEntries(mWorkingSet.mNameTable, xpti_ArrayAppender, + array); + + return array->Enumerate(_retval); +} + +/* void autoRegisterInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces() +{ + nsCOMPtr fileList; + xptiWorkingSet workingSet; + AutoRegMode mode; + + if(!workingSet.IsValid()) + return NS_ERROR_UNEXPECTED; + + // We re-read the manifest rather than muck with the 'live' one. + // It is OK if this fails. + // XXX But we should track failure as a warning. + xptiManifest::Read(this, workingSet); + + // Grovel for all the typelibs we can find (in .xpt or .zip, .jar,...). + if(!BuildFileList(getter_AddRefs(fileList)) || !fileList) + return NS_ERROR_UNEXPECTED; + + // DEBUG_DumpFileList(fileList); + + // Check to see how much work we need to do. + mode = DetermineAutoRegStrategy(fileList, workingSet); + + switch(mode) + { + case NO_FILES_CHANGED: + return NS_OK; + case MAYBE_ONLY_ADDITIONS: + // This might fallback and do a full validation + // (by calling DoFullValidationMergeFromFileList) so we let + // it possibly modify 'mode'. + if(!AttemptAddOnlyFromFileList(fileList, workingSet, &mode)) + return NS_ERROR_UNEXPECTED; + break; + case FULL_VALIDATION_REQUIRED: + if(!DoFullValidationMergeFromFileList(fileList, workingSet)) + return NS_ERROR_UNEXPECTED; + break; + default: + NS_ASSERTION(0,"switch missing a case"); + return NS_ERROR_UNEXPECTED; + } + + // XXX Is failure to write the file a good reason to not merge? + if(!xptiManifest::Write(this, workingSet)) + return NS_ERROR_UNEXPECTED; + + if(!MergeWorkingSets(mWorkingSet, workingSet)) + return NS_ERROR_UNEXPECTED; + +// DEBUG_DumpFileListInWorkingSet(mWorkingSet); + + return NS_OK; +} + +/***************************************************************************/ + +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager() +{ + return xptiInterfaceInfoManager::GetInterfaceInfoManager(); +} + +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager() +{ + xptiInterfaceInfoManager::FreeInterfaceInfoManager(); +} + diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiManifest.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiManifest.cpp new file mode 100644 index 00000000000..8d378354918 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiManifest.cpp @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiManifest. */ + +#include "xptiprivate.h" + + +static const char g_MainManifestFilename[] = "xpti.dat"; +static const char g_TempManifestFilename[] = "xptitemp.dat"; + +static const char g_Disclaimer[] = "# Generated file. ** DO NOT EDIT! **"; + +static const char g_TOKEN_Files[] = "Files"; +static const char g_TOKEN_ArchiveItems[] = "ArchiveItems"; +static const char g_TOKEN_Interfaces[] = "Interfaces"; +static const char g_TOKEN_Header[] = "Header"; +static const char g_TOKEN_Version[] = "Version"; + +static const int g_VERSION_MAJOR = 1; +static const int g_VERSION_MINOR = 0; + +// This is used to make PR_sscanf for strings safer. We refuse to even +// attempt to do a PR_sscanf from a line longer than this. +static const int g_MAX_LINE_LEN = 256; + +/***************************************************************************/ + +static PRBool +WriteFormatted(FILE* file, const char* fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + char* buf = PR_vsmprintf(fmt, ap); + va_end(ap); + + if(!buf) + return PR_FALSE; + + size_t len = PL_strlen(buf); + + PRBool result = (len == fwrite(buf, 1, len, file)); + + PR_smprintf_free(buf); + + return result; +} + +static PR_CALLBACK PRIntn +xpti_InterfaceWriter(PLHashEntry *he, PRIntn i, void *arg) +{ + xptiInterfaceInfo* info = (xptiInterfaceInfo*) he->value; + FILE* file = (FILE*) arg; + + if(!info->IsValid()) + return HT_ENUMERATE_STOP; + + char* iidStr = info->GetTheIID()->ToString(); + if(!iidStr) + return HT_ENUMERATE_STOP; + + const xptiTypelib& typelib = info->GetTypelibRecord(); + + PRBool success = WriteFormatted(file, "%d,%s,%s,%d,%d\n", + (int) i, + info->GetTheName(), + iidStr, + (int) typelib.GetFileIndex(), + (int) (typelib.IsZip() ? + typelib.GetZipItemIndex() : -1)); + + nsCRT::free(iidStr); + + return success ? HT_ENUMERATE_NEXT : HT_ENUMERATE_STOP; +} + +// static +PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet& aWorkingSet) +{ + + PRBool succeeded = PR_FALSE; + FILE* file = nsnull; + PRUint32 i; + PRIntn interfaceCount = 0; + + nsCOMPtr tempFile; + if(!aMgr->GetComponentsDir(getter_AddRefs(tempFile)) || !tempFile) + return PR_FALSE; + + if(NS_FAILED(tempFile->Append(g_TempManifestFilename))) + return PR_FALSE; + + // exist via "goto out;" from here on... + + + if(NS_FAILED(tempFile->OpenANSIFileDesc("w", &file)) || !file) + { + goto out; + } + + // write file header comments + + if(!WriteFormatted(file, "%s\n", g_Disclaimer)) + goto out; + + // write the [Header] block and version number. + + if(!WriteFormatted(file, "\n[%s,%d]\n", g_TOKEN_Header, 1)) + goto out; + + if(!WriteFormatted(file, "%d,%s,%d,%d\n", + 0, g_TOKEN_Version, g_VERSION_MAJOR, g_VERSION_MINOR)) + goto out; + + // write Files list + + if(!WriteFormatted(file, "\n[%s,%d]\n", + g_TOKEN_Files, + (int) aWorkingSet.GetFileCount())) + goto out; + + for(i = 0; i < aWorkingSet.GetFileCount(); i++) + { + if(!WriteFormatted(file, "%d,%s,%lld,%lld\n", + (int) i, + aWorkingSet.GetFileAt(i).GetName(), + PRInt64(aWorkingSet.GetFileAt(i).GetSize()), + PRInt64(aWorkingSet.GetFileAt(i).GetDate()))) + goto out; + } + + // write ArchiveItems list + + if(!WriteFormatted(file, "\n[%s,%d]\n", + g_TOKEN_ArchiveItems, + (int) aWorkingSet.GetZipItemCount())) + goto out; + + for(i = 0; i < aWorkingSet.GetZipItemCount(); i++) + { + if(!WriteFormatted(file, "%d,%s\n", + (int) i, + aWorkingSet.GetZipItemAt(i).GetName())) + goto out; + } + + // write the Interfaces list + + interfaceCount = aWorkingSet.mNameTable->nentries; + + if(!WriteFormatted(file, "\n[%s,%d]\n", + g_TOKEN_Interfaces, + (int) interfaceCount)) + goto out; + + if(interfaceCount != + PL_HashTableEnumerateEntries(aWorkingSet.mNameTable, + xpti_InterfaceWriter, file)) + goto out; + + + if(0 == fclose(file)) + { + succeeded = PR_TRUE; + } + file = nsnull; + +out: + if(file) + fclose(file); + + if(succeeded) + { + // delete the old file and rename this + nsCOMPtr mainFile; + if(!aMgr->GetComponentsDir(getter_AddRefs(mainFile)) || !mainFile) + return PR_FALSE; + + if(NS_FAILED(mainFile->Append(g_MainManifestFilename))) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(mainFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mainFile->Delete(PR_FALSE))) + return PR_FALSE; + + // XXX Would prefer MoveTo with a 'null' newdir, the but nsILocalFile + // implementation are broken. + // http://bugzilla.mozilla.org/show_bug.cgi?id=33098 + + nsCOMPtr dir; + if(!aMgr->GetComponentsDir(getter_AddRefs(dir)) || !dir) + return PR_FALSE; + + if(NS_FAILED(tempFile->CopyTo(dir, g_MainManifestFilename))) + return PR_FALSE; + } + + return succeeded; +} + + +static char* +ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr, + PRUint32* pLength) +{ + FILE* file = nsnull; + PRUint32 flen; + PRInt64 fileSize; + char* whole = nsnull; + + nsCOMPtr aFile; + if(!aMgr->GetComponentsDir(getter_AddRefs(aFile)) || !aFile) + return nsnull; + + if(NS_FAILED(aFile->Append(g_MainManifestFilename))) + return nsnull; + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + return nsnull; + + whole = new char[flen]; + if (!whole) + return nsnull; + + // all exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenANSIFileDesc("rb", &file)) || !file) + goto out; + + if(flen > fread(whole, 1, flen, file)) + goto out; + + out: + if(file) + fclose(file); + *pLength = flen; + return whole; +} + +/***************************************************/ +class ManifestLineReader +{ +public: + ManifestLineReader() : mBase(nsnull) {} + ~ManifestLineReader() {} + + void Init(char* base, PRUint32 flen) + {mBase = mCur = mNext = base; + mLength = 0; + mLimit = base + flen;} + + PRBool NextLine(); + char* LinePtr() {return mCur;} + PRUint32 LineLength() {return mLength;} + +private: + char* mCur; + PRUint32 mLength; + char* mNext; + char* mBase; + char* mLimit; +}; + +PRBool +ManifestLineReader::NextLine() +{ + if(mNext == mLimit) + return PR_FALSE; + + mCur = mNext; + mLength = 0; + + while(mNext < mLimit) + { + char c = *(mNext); + if(c == '\n' || c == '\r') + { + do + { + *(mNext++) = '\0'; + char c = *(mNext); + if(c != '\n' && c != '\r') + return PR_TRUE; + } while(mNext < mLimit); + return PR_TRUE; + } + ++mNext; + ++mLength; + } + return PR_FALSE; +} +/***************************************************/ + +static +PRBool ReadSectionHeader(ManifestLineReader& reader, + const char *token, int minCount, + char* name, int* count) +{ + while(1) + { + if(!reader.NextLine()) + break; + if(*reader.LinePtr() == '[') + { + if(reader.LineLength() > g_MAX_LINE_LEN) + break; + if(2 == PR_sscanf(reader.LinePtr(), "[%[^','],%d]", + name, count) && + 0 == PL_strcmp(name, token) && + *count >= minCount) + { + return PR_TRUE; + } + break; + } + } + return PR_FALSE; +} + + +// static +PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet& aWorkingSet) +{ + char* whole = nsnull; + char* name = nsnull; + char* iidStr = nsnull; + PRBool succeeded = PR_FALSE; + PRUint32 flen; + ManifestLineReader reader; + int headerCount = 0; + int fileCount = 0; + int zipItemCount = -1; + int interfaceCount = 0; + int i; + int index; + int major; + int minor; + PRInt64 size; + PRInt64 date; + + whole = ReadManifestIntoMemory(aMgr, &flen); + if(!whole) + return PR_FALSE; + + reader.Init(whole, flen); + + // all exits from on here should be via 'goto out' + + // We are going to scanf into these buffers, let's make them big. + name = new char[g_MAX_LINE_LEN]; + if(!name) + goto out; + + iidStr = new char[g_MAX_LINE_LEN]; + if(!iidStr) + goto out; + + // Look for "Header" section + + // This version accepts only version 1,0. We also freak if the header + // has more than one entry. The rationale is that we want to force an + // autoreg if the xpti.dat file was written by *any* other version of + // the software. Future versions may wish to support updating older + // manifests in some interesting way. + + if(!ReadSectionHeader(reader, g_TOKEN_Header, 1, name, &headerCount)) + goto out; + + // get the version + + if(headerCount != 1) + goto out; + + if(!reader.NextLine()) + goto out; + + if(reader.LineLength() > g_MAX_LINE_LEN) + goto out; + + if(4 != PR_sscanf(reader.LinePtr(), "%d,%[^','],%d,%d", + &index, name, &major, &minor) || + 0 != index || + 0 != PL_strcmp(name, g_TOKEN_Version) || + major != g_VERSION_MAJOR || + minor != g_VERSION_MINOR) + { + goto out; + } + + // Look for "Files" section + + if(!ReadSectionHeader(reader, g_TOKEN_Files, 1, name, &fileCount)) + goto out; + + + // Alloc room in the WorkingSet for the filearray. + + if(!aWorkingSet.NewFileArray(fileCount)) + goto out; + + // Read the file records + + for(i = 0; i < fileCount; ++i) + { + if(!reader.NextLine()) + goto out; + + if(reader.LineLength() > g_MAX_LINE_LEN) + goto out; + + if(4 != PR_sscanf(reader.LinePtr(), "%d,%[^','],%lld,%lld", + &index, name, &size, &date) || + i != index || + !*name) + { + goto out; + } + + // Append a new file record to the array. + + aWorkingSet.AppendFile( + xptiFile(nsInt64(size), nsInt64(date), name, &aWorkingSet)); + } + + // Look for "ZipItems" section + + if(!ReadSectionHeader(reader, g_TOKEN_ArchiveItems, 0, name, &zipItemCount)) + goto out; + + // Alloc room in the WorkingSet for the zipItemarray. + + if(zipItemCount) + if(!aWorkingSet.NewZipItemArray(zipItemCount)) + goto out; + + // Read the zipItem records + + for(i = 0; i < zipItemCount; ++i) + { + if(!reader.NextLine()) + goto out; + + if(reader.LineLength() > g_MAX_LINE_LEN) + goto out; + + if(2 != PR_sscanf(reader.LinePtr(), "%d,%[^',']", + &index, name) || + i != index || + !*name) + { + goto out; + } + + // Append a new zipItem record to the array. + + aWorkingSet.AppendZipItem(xptiZipItem(name, &aWorkingSet)); + } + + // Look for "Interfaces" section + + if(!ReadSectionHeader(reader, g_TOKEN_Interfaces, 1, name, &interfaceCount)) + goto out; + + // Read the interface records + + for(i = 0; i < interfaceCount; ++i) + { + int fileIndex; + int zipItemIndex; + nsIID iid; + xptiInterfaceInfo* info; + xptiTypelib typelibRecord; + + if(!reader.NextLine()) + goto out; + + if(reader.LineLength() > g_MAX_LINE_LEN) + goto out; + + if(5 != PR_sscanf(reader.LinePtr(), "%d,%[^','],%[^','],%d,%d", + &index, name, iidStr, &fileIndex, &zipItemIndex) || + i != index || + !*name || + !*iidStr || + !iid.Parse(iidStr) || + fileIndex < 0 || + fileIndex >= fileCount || + (zipItemIndex != -1 && zipItemIndex >= zipItemCount)) + { + goto out; + } + + // Build an InterfaceInfo and hook it in. + + if(zipItemIndex == -1) + typelibRecord.Init(fileIndex); + else + typelibRecord.Init(fileIndex, zipItemIndex); + info = new xptiInterfaceInfo(name, iid, typelibRecord, aWorkingSet); + if(!info) + { + goto out; + } + + NS_ADDREF(info); + if(!info->IsValid()) + { + // XXX bad! + NS_RELEASE(info); + goto out; + } + + // The name table now owns the reference we AddRef'd above + PL_HashTableAdd(aWorkingSet.mNameTable, info->GetTheName(), info); + PL_HashTableAdd(aWorkingSet.mIIDTable, info->GetTheIID(), info); + } + + // success! + + succeeded = PR_TRUE; + + out: + if(whole) + delete [] whole; + if(name) + delete [] name; + if(iidStr) + delete [] iidStr; + + if(!succeeded) + { + // Cleanup the WorkingSet on failure. + aWorkingSet.InvalidateInterfaceInfos(); + aWorkingSet.ClearHashTables(); + aWorkingSet.ClearFiles(); + } + return succeeded; +} + + + + diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp new file mode 100644 index 00000000000..366fbb88944 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiTypelibGuts. */ + +#include "xptiprivate.h" + +xptiTypelibGuts::xptiTypelibGuts(XPTHeader* aHeader) + : mHeader(aHeader), + mInfoArray(nsnull) +{ + NS_ASSERTION(mHeader, "bad param"); + + if(mHeader->num_interfaces) + { + mInfoArray = new xptiInterfaceInfo*[GetInfoCount()]; + if(mInfoArray) + memset(mInfoArray, 0, sizeof(xptiInterfaceInfo*) * GetInfoCount()); + else + mHeader = nsnull; + } +} + +xptiTypelibGuts::~xptiTypelibGuts() +{ + if(mHeader && mInfoArray) + for(PRUint16 i = 0; i < GetInfoCount(); ++i) + NS_IF_RELEASE(mInfoArray[i]); + delete [] mInfoArray; +} + +xptiTypelibGuts* +xptiTypelibGuts::Clone() +{ + xptiTypelibGuts* clone = new xptiTypelibGuts(mHeader); + if(clone && clone->IsValid()) + for(PRUint16 i = 0; i < GetInfoCount(); ++i) + clone->SetInfoAt(i, GetInfoAtNoAddRef(i)); + return clone; +} + +nsresult +xptiTypelibGuts::GetInfoAt(PRUint16 i, xptiInterfaceInfo** ptr) +{ + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(mInfoArray,"bad state!"); + NS_ASSERTION(i < GetInfoCount(),"bad param!"); + NS_ASSERTION(ptr,"bad param!"); + + NS_IF_ADDREF(*ptr = mInfoArray[i]); + return NS_OK; +} + +xptiInterfaceInfo* +xptiTypelibGuts::GetInfoAtNoAddRef(PRUint16 i) +{ + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(mInfoArray,"bad state!"); + NS_ASSERTION(i < GetInfoCount(),"bad param!"); + + return mInfoArray[i]; +} + + +nsresult +xptiTypelibGuts::SetInfoAt(PRUint16 i, xptiInterfaceInfo* ptr) +{ + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(mInfoArray,"bad state!"); + NS_ASSERTION(i < GetInfoCount(),"bad param!"); + + NS_IF_ADDREF(ptr); + NS_IF_RELEASE(mInfoArray[i]); + mInfoArray[i] = ptr; + return NS_OK; +} diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp new file mode 100644 index 00000000000..849ddfc70a5 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiWorkingSet. */ + +#include "xptiprivate.h" + +#define XPTI_STRING_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_HASHTABLE_SIZE 128 + +static PR_CALLBACK PLHashNumber +xpti_HashIID(const void *key) +{ + return ((nsID*)key)->m0; +} + +static PR_CALLBACK PRIntn +xpti_CompareIIDs(const void *v1, const void *v2) +{ + return (PRIntn) ((const nsID*)v1)->Equals(*((const nsID*)v2)); +} + +xptiWorkingSet::xptiWorkingSet() + : mFileCount(0), + mMaxFileCount(0), + mFileArray(nsnull), + mZipItemCount(0), + mMaxZipItemCount(0), + mZipItemArray(nsnull), + mStringArena(XPT_NewArena(XPTI_STRING_ARENA_BLOCK_SIZE, sizeof(char), + "xptiWorkingSet strings")), + mStructArena(XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double), + "xptiWorkingSet structs")), + mNameTable(PL_NewHashTable(XPTI_HASHTABLE_SIZE, PL_HashString, + PL_CompareStrings, PL_CompareValues, + nsnull, nsnull)), + mIIDTable(PL_NewHashTable(XPTI_HASHTABLE_SIZE, xpti_HashIID, + xpti_CompareIIDs, PL_CompareValues, + nsnull, nsnull)), + mMergeOffsetMap(nsnull) +{ + // do nothing else... +} + +PRBool +xptiWorkingSet::IsValid() const +{ + return (mFileCount == 0 || mFileArray) && + (mZipItemCount == 0 || mZipItemArray) && + mStringArena && + mStructArena && + mNameTable && + mIIDTable; +} + +static PR_CALLBACK PRIntn +xpti_Remover(PLHashEntry *he, PRIntn i, void *arg) +{ + return HT_ENUMERATE_REMOVE; +} + +static PR_CALLBACK PRIntn +xpti_ReleaseAndRemover(PLHashEntry *he, PRIntn i, void *arg) +{ + nsIInterfaceInfo* ii = (nsIInterfaceInfo*) he->value; + NS_RELEASE(ii); + return HT_ENUMERATE_REMOVE; +} + + +static PR_CALLBACK PRIntn +xpti_Invalidator(PLHashEntry *he, PRIntn i, void *arg) +{ + ((xptiInterfaceInfo*)he->value)->Invalidate(); + return HT_ENUMERATE_NEXT; +} + +void +xptiWorkingSet::InvalidateInterfaceInfos() +{ + if(mNameTable) + PL_HashTableEnumerateEntries(mNameTable, xpti_Invalidator, nsnull); +} + +void +xptiWorkingSet::ClearHashTables() +{ + if(mNameTable) + PL_HashTableEnumerateEntries(mNameTable, xpti_Remover, nsnull); + + if(mIIDTable) + PL_HashTableEnumerateEntries(mIIDTable, xpti_ReleaseAndRemover, nsnull); +} + +void +xptiWorkingSet::ClearFiles() +{ + if(mFileArray) + delete [] mFileArray; + mFileArray = nsnull; + mMaxFileCount = 0; + mFileCount = 0; +} + +void +xptiWorkingSet::ClearZipItems() +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemArray = nsnull; + mMaxZipItemCount = 0; + mZipItemCount = 0; +} + +xptiWorkingSet::~xptiWorkingSet() +{ + ClearFiles(); + ClearZipItems(); + ClearHashTables(); + + if(mNameTable) + PL_HashTableDestroy(mNameTable); + + if(mIIDTable) + PL_HashTableDestroy(mIIDTable); + + if(mFileArray) + delete [] mFileArray; + + if(mZipItemArray) + delete [] mZipItemArray; + + // Destroy arenas last in case they are referenced in other members' dtors. + + if(mStringArena) + { +#ifdef DEBUG + XPT_DumpStats(mStringArena); +#endif + XPT_DestroyArena(mStringArena); + } + + if(mStructArena) + { +#ifdef DEBUG + XPT_DumpStats(mStructArena); +#endif + XPT_DestroyArena(mStructArena); + } +} + +PRBool +xptiWorkingSet::NewFileArray(PRUint32 count) +{ + if(mFileArray) + delete [] mFileArray; + mFileCount = 0; + mFileArray = new xptiFile[count]; + if(!mFileArray) + { + mMaxFileCount = 0; + return PR_FALSE; + } + mMaxFileCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendFileArray(PRUint32 count) +{ + if(mFileArray && count < mMaxFileCount) + return PR_TRUE; + + xptiFile* newArray = new xptiFile[count]; + if(!newArray) + return PR_FALSE; + + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount; ++i) + newArray[i] = mFileArray[i]; + delete [] mFileArray; + } + mFileArray = newArray; + mMaxFileCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::NewZipItemArray(PRUint32 count) +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemCount = 0; + mZipItemArray = new xptiZipItem[count]; + if(!mZipItemArray) + { + mMaxZipItemCount = 0; + return PR_FALSE; + } + mMaxZipItemCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendZipItemArray(PRUint32 count) +{ + if(mZipItemArray && count < mMaxZipItemCount) + return PR_TRUE; + + xptiZipItem* newArray = new xptiZipItem[count]; + if(!newArray) + return PR_FALSE; + + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount; ++i) + newArray[i] = mZipItemArray[i]; + delete [] mZipItemArray; + } + mZipItemArray = newArray; + mMaxZipItemCount = count; + return PR_TRUE; +} diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiZipItem.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiZipItem.cpp new file mode 100644 index 00000000000..3c6a94f4f88 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiZipItem.cpp @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Implementation of xptiZipItem. */ + +#include "xptiprivate.h" + + +xptiZipItem::xptiZipItem() + : mName(nsnull), + mGuts(nsnull) +{ + // empty +} + +xptiZipItem::xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet, + XPTHeader* aHeader /*= nsnull */) + + : mName(aName), + mGuts(nsnull) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); + + if(aHeader) + SetHeader(aHeader); +} + +xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet, + PRBool cloneGuts) + : mName(nsnull), + mGuts(nsnull) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); + + if(cloneGuts && r.mGuts) + mGuts = r.mGuts->Clone(); +} + +xptiZipItem::~xptiZipItem() +{ + if(mGuts) + delete mGuts; +} + +PRBool +xptiZipItem::SetHeader(XPTHeader* aHeader) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + + mGuts = new xptiTypelibGuts(aHeader); + if(mGuts && !mGuts->IsValid()) + { + delete mGuts; + mGuts = nsnull; + } + return mGuts != nsnull; +} diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiprivate.h b/mozilla/xpcom/reflect/xptinfo/src/xptiprivate.h new file mode 100644 index 00000000000..058ff198db2 --- /dev/null +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiprivate.h @@ -0,0 +1,536 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Library-private header for Interface Info system. */ + +#ifndef xptiprivate_h___ +#define xptiprivate_h___ + +#include "nscore.h" +#include "nsISupports.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" + +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" + +#include "nsIServiceManager.h" +#include "nsIFile.h" +#include "nsILocalFile.h" +#include "nsSpecialSystemDirectory.h" + +#include "nsISupportsArray.h" +#include "nsInt64.h" + +#include "nsQuickSort.h" +#include "nsIZipReader.h" +#include "nsIInputStream.h" + +#include "plstr.h" +#include "prprf.h" + +#include +#include + +/***************************************************************************/ + +class xptiFile; +class xptiInterfaceInfo; +class xptiInterfaceInfoManager; +class xptiInterfaceGuts; +class xptiTypelibGuts; +class xptiWorkingSet; + +/***************************************************************************/ + +class xptiTypelib +{ +public: + // No ctors or dtors so that we can be in a union in xptiInterfaceInfo. + // Allow automatic shallow copies. + + uint16 GetFileIndex() const {return mFileIndex;} + uint16 GetZipItemIndex() const {return mZipItemIndex;} + + enum {NOT_ZIP = 0xffff}; + + PRBool IsZip() const {return mZipItemIndex != NOT_ZIP;} + + void Init(uint16 aFileIndex, uint16 aZipItemIndex = NOT_ZIP) + {mFileIndex = aFileIndex; mZipItemIndex = aZipItemIndex;} + + PRBool Equals(const xptiTypelib& r) const + {return mFileIndex == r.mFileIndex && + mZipItemIndex == r.mZipItemIndex;} + +private: + uint16 mFileIndex; + uint16 mZipItemIndex; +}; + +/***************************************************************************/ + +class xptiTypelibGuts +{ +public: + xptiTypelibGuts(); // not implemented + xptiTypelibGuts(XPTHeader* aHeader); + ~xptiTypelibGuts(); + + PRBool IsValid() const {return mHeader != nsnull;} + XPTHeader* GetHeader() {return mHeader;} + PRUint16 GetInfoCount() const {return mHeader->num_interfaces;} + nsresult SetInfoAt(PRUint16 i, xptiInterfaceInfo* ptr); + nsresult GetInfoAt(PRUint16 i, xptiInterfaceInfo** ptr); + xptiInterfaceInfo* GetInfoAtNoAddRef(PRUint16 i); + xptiTypelibGuts* Clone(); + +private: + XPTHeader* mHeader; // hold pointer into arena + xptiInterfaceInfo** mInfoArray; +}; + +/***************************************************************************/ + +class xptiFile +{ +public: + const nsInt64& GetSize() const {return mSize;} + const nsInt64& GetDate() const {return mDate;} + const char* GetName() const {return mName;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiFile(); + + xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + const char* aName, + xptiWorkingSet* aWorkingSet, + XPTHeader* aHeader = nsnull); + + xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet, + PRBool cloneGuts); + + ~xptiFile(); + + PRBool SetHeader(XPTHeader* aHeader); + + PRBool Equals(const xptiFile& r) const + { + return mSize == r.mSize && + mDate == r.mDate && + 0 == PL_strcmp(mName, r.mName); + } + + xptiFile(const xptiFile& r) {CopyFields(r);} + xptiFile& operator= (const xptiFile& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiFile& r) + { + mSize = r.mSize; + mDate = r.mDate; + mName = r.mName; + if(mGuts) + delete mGuts; + if(r.mGuts) + mGuts = r.mGuts->Clone(); + else + mGuts = nsnull; + } + +private: + nsInt64 mSize; + nsInt64 mDate; + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // new/delete +}; + +/***************************************************************************/ + +class xptiZipItem +{ +public: + const char* GetName() const {return mName;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiZipItem(); + + xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet, + XPTHeader* aHeader = nsnull); + + xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet, + PRBool cloneGuts); + + ~xptiZipItem(); + + PRBool SetHeader(XPTHeader* aHeader); + + PRBool Equals(const xptiZipItem& r) const + { + return 0 == PL_strcmp(mName, r.mName); + } + + xptiZipItem(const xptiZipItem& r) {CopyFields(r);} + xptiZipItem& operator= (const xptiZipItem& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiZipItem& r) + { + mName = r.mName; + if(mGuts) + delete mGuts; + if(r.mGuts) + mGuts = r.mGuts->Clone(); + else + mGuts = nsnull; + } + +private: + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // new/delete +}; + +/***************************************************************************/ + +class xptiWorkingSet +{ +public: + xptiWorkingSet(); + ~xptiWorkingSet(); + + PRBool IsValid() const; + + void InvalidateInterfaceInfos(); + void ClearHashTables(); + void ClearFiles(); + void ClearZipItems(); + + // utility methods... + + xptiTypelibGuts* GetTypelibGuts(const xptiTypelib& typelib) + { + return typelib.IsZip() ? + GetZipItemAt(typelib.GetZipItemIndex()).GetGuts() : + GetFileAt(typelib.GetFileIndex()).GetGuts(); + } + + // FileArray stuff... + + PRUint32 GetFileCount() const {return mFileCount;} + PRUint32 GetFileFreeSpace() + {return mFileArray ? mMaxFileCount - mFileCount : 0;} + + xptiFile& GetFileAt(PRUint32 i) const + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + return mFileArray[i]; + } + + void SetFileAt(PRUint32 i, const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + mFileArray[i] = r; + } + + void AppendFile(const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(mFileCount < mMaxFileCount, "bad param!"); + mFileArray[mFileCount++] = r; + } + + PRBool NewFileArray(PRUint32 count); + PRBool ExtendFileArray(PRUint32 count); + + // ZipItemArray stuff... + + PRUint32 GetZipItemCount() const {return mZipItemCount;} + PRUint32 GetZipItemFreeSpace() + {return mZipItemArray ? mMaxZipItemCount - mZipItemCount : 0;} + + xptiZipItem& GetZipItemAt(PRUint32 i) const + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + return mZipItemArray[i]; + } + + void SetZipItemAt(PRUint32 i, const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + mZipItemArray[i] = r; + } + + void AppendZipItem(const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(mZipItemCount < mMaxZipItemCount, "bad param!"); + mZipItemArray[mZipItemCount++] = r; + } + + PRBool NewZipItemArray(PRUint32 count); + PRBool ExtendZipItemArray(PRUint32 count); + + // Arena stuff... + + XPTArena* GetStringArena() {return mStringArena;} + XPTArena* GetStructArena() {return mStructArena;} + + +private: + PRUint32 mFileCount; + PRUint32 mMaxFileCount; + xptiFile* mFileArray; // using new[] and delete[] + + PRUint32 mZipItemCount; + PRUint32 mMaxZipItemCount; + xptiZipItem* mZipItemArray; // using new[] and delete[] + + XPTArena* mStringArena; + XPTArena* mStructArena; + +public: + // XXX make these private with accessors + PLHashTable* mNameTable; + PLHashTable* mIIDTable; + PRUint32* mMergeOffsetMap; // always in an arena +}; + +/***************************************************************************/ + +// XXX could move this class to xptiInterfaceInfo.cpp. + +class xptiInterfaceGuts +{ +public: + + uint16 mMethodBaseIndex; + uint16 mConstantBaseIndex; + nsIInterfaceInfo* mParent; + XPTInterfaceDescriptor* mDescriptor; + xptiTypelib mTypelib; + xptiWorkingSet* mWorkingSet; + + xptiInterfaceGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + : mMethodBaseIndex(0), + mConstantBaseIndex(0), + mParent(nsnull), + mDescriptor(aDescriptor), + mTypelib(aTypelib), + mWorkingSet(aWorkingSet) {} + + ~xptiInterfaceGuts() {NS_IF_RELEASE(mParent);} +}; + +/***************************************************************************/ + +class xptiInterfaceInfo : public nsIInterfaceInfo +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFO + +public: + xptiInterfaceInfo(); // not implemented + + xptiInterfaceInfo(const char* name, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet& aWorkingSet); + + virtual ~xptiInterfaceInfo(); + + enum { + NOT_RESOLVED = 0, + PARTIALLY_RESOLVED = 1, + FULLY_RESOLVED = 2, + RESOLVE_FAILED = 3 + }; + + PRBool IsValid() const + {return mName != nsnull;} + + char GetResolveState() const + {return IsValid() ? mName[-1] : (char) RESOLVE_FAILED;} + + PRBool IsFullyResolved() const + {return GetResolveState() == (char) FULLY_RESOLVED;} + + PRBool HasInterfaceRecord() const + {int s = (int) GetResolveState(); + return + (s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface; + } + + const xptiTypelib& GetTypelibRecord() const + {return HasInterfaceRecord() ? mInterface->mTypelib : mTypelib;} + + const nsID* GetTheIID() const {return &mIID;} + const char* GetTheName() const {return mName;} + + PRBool PartiallyResolve(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet); + + void Invalidate() + { + if(IsValid()) + { + xptiTypelib typelib = GetTypelibRecord(); + mTypelib = typelib; + mName = nsnull; + } + } + +private: + void SetResolvedState(int state) + {NS_ASSERTION(IsValid(),"bad state"); mName[-1] = (char) state;} + + PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull); + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);} + + NS_IMETHOD GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type); +private: + nsID mIID; + char* mName; // This is in arena (not free'd) and mName[-1] is a flag. + + union { + xptiTypelib mTypelib; // Valid only until resolved. + xptiInterfaceGuts* mInterface; // Valid only after resolved. + }; +}; + +/***************************************************************************/ + +class xptiManifest +{ +public: + static PRBool Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet& aWorkingSet); + + static PRBool Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet& aWorkingSet); + + xptiManifest(); // no implementation +}; + +/***************************************************************************/ + +class xptiInterfaceInfoManager : public nsIInterfaceInfoManager +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFOMANAGER + +public: + virtual ~xptiInterfaceInfoManager(); + static xptiInterfaceInfoManager* GetInterfaceInfoManager(); + static void FreeInterfaceInfoManager(); + + xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;} + + PRBool LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet = nsnull); + + PRBool GetComponentsDir(nsILocalFile** aDir); + +private: + xptiInterfaceInfoManager(); + + enum AutoRegMode { + NO_FILES_CHANGED = 0, + MAYBE_ONLY_ADDITIONS, + FULL_VALIDATION_REQUIRED + }; + + PRBool BuildFileList(nsISupportsArray** aFileList); + + PRBool PopulateWorkingSetFromManifest(xptiWorkingSet& aWorkingSet); + PRBool WriteManifest(xptiWorkingSet& aWorkingSet); + + XPTHeader* ReadXPTFile(nsILocalFile* aFile, xptiWorkingSet& aWorkingSet); + + XPTHeader* ReadXPTFileFromZip(nsILocalFile* file, + const char* itemName, + xptiWorkingSet& aWorkingSet); + + XPTHeader* ReadXPTFileFromOpenZip(nsIZipReader * zip, + nsIZipEntry* entry, + const char* itemName, + xptiWorkingSet& aWorkingSet); + + AutoRegMode DetermineAutoRegStrategy(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet); + + PRBool AttemptAddOnlyFromFileList(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet, + AutoRegMode* pmode); + + PRBool DoFullValidationMergeFromFileList(nsISupportsArray* aFileList, + xptiWorkingSet& aWorkingSet); + + PRBool VerifyAndAddInterfaceIfNew(xptiWorkingSet& aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceInfo** infoAdded); + + PRBool MergeWorkingSets(xptiWorkingSet& aDestWorkingSet, + xptiWorkingSet& aSrcWorkingSet); + + PRBool DEBUG_DumpFileList(nsISupportsArray* aFileList); + PRBool DEBUG_DumpFileListInWorkingSet(xptiWorkingSet& aWorkingSet); + +private: + xptiWorkingSet mWorkingSet; +}; + +#if 0 + + + +#endif + + +#endif /* xptiprivate_h___ */ diff --git a/mozilla/xpcom/typelib/xpt/public/xpt_arena.h b/mozilla/xpcom/typelib/xpt/public/xpt_arena.h new file mode 100644 index 00000000000..4e4880a7b4d --- /dev/null +++ b/mozilla/xpcom/typelib/xpt/public/xpt_arena.h @@ -0,0 +1,113 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* + * Simple arena allocator for xpt (which avoids using NSPR). + */ + +#ifndef __xpt_arena_h__ +#define __xpt_arena_h__ + +#include "prtypes.h" +#include +#include + + +/* + * The linkage of XPT API functions differs depending on whether the file is + * used within the XPT library or not. Any source file within the XPT + * library should define EXPORT_XPT_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPT_API +#define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPT_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#else +#ifdef _WIN32 +# define XPT_PUBLIC_API(t) _declspec(dllimport) t +# define XPT_PUBLIC_DATA(t) _declspec(dllimport) t +#else +# define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPT_PUBLIC_DATA(t) t +#endif +#endif +#define XPT_FRIEND_API(t) XPT_PUBLIC_API(t) +#define XPT_FRIEND_DATA(t) XPT_PUBLIC_DATA(t) + +PR_BEGIN_EXTERN_C + +/* + * Simple Arena support. Use with caution! + */ + +typedef struct XPTArena XPTArena; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name); + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena); + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size); + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s); + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void* block); + +/* --------------------------------------------------------- */ + +#define XPT_MALLOC(_arena, _bytes) \ + XPT_ArenaMalloc((_arena), (_bytes)) + +#ifdef DEBUG +#define XPT_FREE(_arena, _ptr) \ + XPT_ArenaFree((_arena), (_ptr)) +#else +#define XPT_FREE(_arena, _ptr) \ + ((void)0) +#endif + +#define XPT_STRDUP(_arena, _s) \ + XPT_ArenaStrDup((_arena), (_s)) + +#define XPT_CALLOC(_arena, _size) XPT_MALLOC((_arena), (_size)) +#define XPT_NEW(_arena, _struct) ((_struct *) XPT_MALLOC((_arena), sizeof(_struct))) +#define XPT_NEWZAP(_arena, _struct) XPT_NEW((_arena), _struct) +#define XPT_DELETE(_arena, _ptr) do{XPT_FREE((_arena), (_ptr)); ((_ptr)) = NULL;}while(0) +#define XPT_FREEIF(_arena, _ptr) do{if ((_ptr)) XPT_FREE((_arena), (_ptr));}while(0) + +/* --------------------------------------------------------- */ + +#define XPT_ASSERT(_expr) assert(_expr) + +PR_END_EXTERN_C + +#endif /* __xpt_arena_h__ */ diff --git a/mozilla/xpcom/typelib/xpt/src/xpt_arena.c b/mozilla/xpcom/typelib/xpt/src/xpt_arena.c new file mode 100644 index 00000000000..50287cee43a --- /dev/null +++ b/mozilla/xpcom/typelib/xpt/src/xpt_arena.c @@ -0,0 +1,315 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Quick arena hack for xpt. */ + +/* XXX This exists because we don't want to drag in NSPR. It *seemed* +* to make more sense to write a quick and dirty arena than to clone +* plarena (like js/src did). This is not optimal, but it works. +* Half of the code here is instrumentation. +*/ + +#include "xpt_arena.h" +#include +#include +#include +#include + +/*************************/ +/* logging stats support */ + +#ifdef DEBUG_jband +#define XPT_ARENA_LOGGING 1 +#endif + +#ifdef XPT_ARENA_LOGGING + +#define LOG_MALLOC(_a, _req, _used) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_MallocCallCount; \ + (_a)->LOG_MallocTotalBytesRequested += (_req); \ + (_a)->LOG_MallocTotalBytesUsed += (_used); \ + } while(0) + +#define LOG_REAL_MALLOC(_a, _size) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_RealMallocCallCount; \ + (_a)->LOG_RealMallocTotalBytesRequested += (_size); \ + } while(0) + +#define LOG_FREE(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_FreeCallCount; \ + } while(0) + +#define LOG_DONE_LOADING(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + (_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount; \ + } while(0) + +#define PRINT_STATS(_a) xpt_DebugPrintArenaStats((_a)) +static void xpt_DebugPrintArenaStats(XPTArena *arena); + +#else /* !XPT_ARENA_LOGGING */ + +#define LOG_MALLOC(_a, _req, _used) ((void)0) +#define LOG_REAL_MALLOC(_a, _size) ((void)0) +#define LOG_FREE(_a) ((void)0) + +#define LOG_DONE_LOADING(_a) ((void)0) +#define PRINT_STATS(_a) ((void)0) + +#endif /* XPT_ARENA_LOGGING */ + +/****************************************************/ + +/* Block header for each block in the arena */ +typedef struct BLK_HDR BLK_HDR; +struct BLK_HDR +{ + BLK_HDR *next; + size_t size; +}; + +#define XPT_MIN_BLOCK_SIZE 32 + +/* XXX this is lame. Should clone the code to do this bitwise */ +#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a))) + +struct XPTArena +{ + BLK_HDR *first; + PRUint8 *next; + size_t space; + size_t alignment; + size_t block_size; + char *name; + +#ifdef XPT_ARENA_LOGGING + PRUint32 LOG_MallocCallCount; + PRUint32 LOG_MallocTotalBytesRequested; + PRUint32 LOG_MallocTotalBytesUsed; + PRUint32 LOG_FreeCallCount; + PRUint32 LOG_LoadingFreeCallCount; + PRUint32 LOG_RealMallocCallCount; + PRUint32 LOG_RealMallocTotalBytesRequested; +#endif /* XPT_ARENA_LOGGING */ +}; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name) +{ + XPTArena *arena = calloc(1, sizeof(XPTArena)); + if (arena) { + XPT_ASSERT(alignment); + if (alignment > sizeof(double)) + alignment = sizeof(double); + arena->alignment = alignment; + + if (block_size < XPT_MIN_BLOCK_SIZE) + block_size = XPT_MIN_BLOCK_SIZE; + arena->block_size = ALIGN_RND(block_size, alignment); + + /* must have room for at least one item! */ + XPT_ASSERT(arena->block_size >= + ALIGN_RND(sizeof(BLK_HDR), alignment) + + ALIGN_RND(1, alignment)); + + if (name) { + arena->name = XPT_STRDUP(arena, name); +#ifdef XPT_ARENA_LOGGING + /* fudge the stats since we are using space in the arena */ + arena->LOG_MallocCallCount = 0; + arena->LOG_MallocTotalBytesRequested = 0; + arena->LOG_MallocTotalBytesUsed = 0; +#endif /* XPT_ARENA_LOGGING */ + } + } + return arena; +} + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena) +{ + BLK_HDR* cur; + BLK_HDR* next; + + cur = arena->first; + while (cur) { + next = cur->next; + free(cur); + cur = next; + } + free(arena); +} + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena) +{ + PRINT_STATS(arena); +} + + +/* +* Our alignment rule is that we always round up the size of each allocation +* so that the 'arena->next' pointer one will point to properly aligned space. +*/ + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size) +{ + PRUint8 *cur; + size_t bytes; + + if (!size) + return NULL; + + if (!arena) { + XPT_ASSERT(0); + return NULL; + } + + bytes = ALIGN_RND(size, arena->alignment); + + LOG_MALLOC(arena, size, bytes); + + if (bytes > arena->space) { + BLK_HDR* new_block; + size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment); + size_t new_space = arena->block_size; + + if (bytes > new_space - block_header_size) + new_space += bytes; + + new_block = (BLK_HDR*) calloc(new_space/arena->alignment, + arena->alignment); + if (!new_block) { + arena->next = NULL; + arena->space = 0; + return NULL; + } + + LOG_REAL_MALLOC(arena, new_space); + + /* link block into the list of blocks for use when we destroy */ + new_block->next = arena->first; + arena->first = new_block; + + /* save other block header info */ + new_block->size = new_space; + + /* set info for current block */ + arena->next = ((PRUint8*)new_block) + block_header_size; + arena->space = new_space - block_header_size; + +#ifdef DEBUG + /* mark block for corruption check */ + memset(arena->next, 0xcd, arena->space); +#endif + } + +#ifdef DEBUG + { + /* do corruption check */ + size_t i; + for (i = 0; i < bytes; ++i) { + XPT_ASSERT(arena->next[i] == 0xcd); + } + /* we guarantee that the block will be filled with zeros */ + memset(arena->next, 0, bytes); + } +#endif + + cur = arena->next; + arena->next += bytes; + arena->space -= bytes; + + return cur; +} + + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s) +{ + size_t len; + char* cur; + + if (!s) + return NULL; + + len = strlen(s)+1; + cur = XPT_ArenaMalloc(arena, len); + memcpy(cur, s, len); + return cur; +} + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena) +{ +#ifdef XPT_ARENA_LOGGING + if (arena) { + LOG_DONE_LOADING(arena); + } +#endif +} + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void *block) +{ + LOG_FREE(arena); +} + +#ifdef XPT_ARENA_LOGGING +static void xpt_DebugPrintArenaStats(XPTArena *arena) +{ + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); + printf("Start xpt arena stats for \"%s\"\n", + arena->name ? arena->name : "unnamed arena"); + printf("\n"); + printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount); + printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested); + printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("\n"); + printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount); + printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0)); + printf("\n"); + printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount); + printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 )); + printf("\n"); + printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount); + printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested); + printf("%d byte block size specified at arena creation time\n", (int) arena->block_size); + printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment); + printf("\n"); + printf("End xpt arena stats\n"); + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); +} +#endif + +/***************************************************************************/ +