From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../xpcom18a4/xpcom/reflect/xptinfo/.cvsignore | 1 + .../xpcom18a4/xpcom/reflect/xptinfo/Makefile.in | 49 + .../xpcom/reflect/xptinfo/public/.cvsignore | 1 + .../xpcom/reflect/xptinfo/public/Makefile.in | 66 + .../reflect/xptinfo/public/nsIInterfaceInfo.idl | 137 ++ .../xptinfo/public/nsIInterfaceInfoManager.idl | 85 + .../xpcom/reflect/xptinfo/public/nsIXPTLoader.idl | 100 + .../xpcom/reflect/xptinfo/public/xptinfo.h | 281 +++ .../xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore | 1 + .../xpcom/reflect/xptinfo/src/Makefile.in | 75 + src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO | 20 + .../xpcom/reflect/xptinfo/src/xptiFile.cpp | 113 ++ .../reflect/xptinfo/src/xptiInterfaceInfo.cpp | 819 ++++++++ .../xptinfo/src/xptiInterfaceInfoManager.cpp | 2126 ++++++++++++++++++++ .../xpcom/reflect/xptinfo/src/xptiManifest.cpp | 710 +++++++ .../xpcom/reflect/xptinfo/src/xptiMisc.cpp | 164 ++ .../xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp | 63 + .../xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp | 432 ++++ .../xpcom/reflect/xptinfo/src/xptiZipItem.cpp | 102 + .../xpcom/reflect/xptinfo/src/xptiZipLoader.cpp | 113 ++ .../xpcom/reflect/xptinfo/src/xptiprivate.h | 981 +++++++++ .../xpcom/reflect/xptinfo/tests/.cvsignore | 2 + .../xpcom/reflect/xptinfo/tests/Makefile.in | 58 + .../reflect/xptinfo/tests/TestInterfaceInfo.cpp | 146 ++ 24 files changed, 6645 insertions(+) create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp (limited to 'src/libs/xpcom18a4/xpcom/reflect/xptinfo') diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in new file mode 100644 index 00000000..d7e3b9c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla 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/MPL/ +# +# 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 the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in new file mode 100644 index 00000000..dbf13d8b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in @@ -0,0 +1,66 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla 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/MPL/ +# +# 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 the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +XPIDL_MODULE = xpcom_xpti + +GRE_MODULE = 1 + +EXPORTS = \ + xptinfo.h \ + $(NULL) + +XPIDLSRCS = \ + nsIInterfaceInfo.idl \ + nsIInterfaceInfoManager.idl \ + nsIXPTLoader.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +include $(topsrcdir)/config/rules.mk + +CFLAGS += -DEXPORT_XPCI_API + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl new file mode 100644 index 00000000..f77dbcfc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* 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); + +// We bend the rules to do a [shared] nsIID (but this is never scriptable) +[ptr] native nsIIDPtrShared(nsIID); + +%{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 InterfaceIID; + + 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); + + PRBool isIID(in nsIIDPtr IID); + + void getNameShared([shared,retval] out string name); + void getIIDShared([shared,retval] out nsIIDPtrShared iid); + + PRBool isFunction(); + + PRBool hasAncestor(in nsIIDPtr iid); + + [notxpcom] nsresult getIIDForParamNoAlloc(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + out nsIID iid); +}; + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl new file mode 100644 index 00000000..48277691 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* The nsIInterfaceInfoManager public declaration. */ + + +#include "nsISupports.idl" +#include "nsIInterfaceInfo.idl" +#include "nsIEnumerator.idl" +#include "nsISimpleEnumerator.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(); + + nsIEnumerator enumerateInterfacesWhoseNamesStartWith(in string prefix); +}; + +[uuid(0ee22850-bc6a-11d5-9134-0010a4e73d9a)] +interface nsIInterfaceInfoSuperManager : nsIInterfaceInfoManager +{ + void addAdditionalManager(in nsIInterfaceInfoManager manager); + void removeAdditionalManager(in nsIInterfaceInfoManager manager); + + PRBool hasAdditionalManagers(); + nsISimpleEnumerator enumerateAdditionalManagers(); +}; + +%{C++ +#define NS_INTERFACEINFOMANAGER_SERVICE_CLASSNAME \ + "Interface Information Manager Service" + +#define NS_INTERFACEINFOMANAGER_SERVICE_CID \ + { /* 13bef784-f8e0-4f96-85c1-09f9ef4f9a19 */ \ + 0x13bef784, 0xf8e0, 0x4f96, \ + {0x85, 0xc1, 0x09, 0xf9, 0xef, 0x4f, 0x9a, 0x19} } + +#define NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID \ + "@mozilla.org/xpti/interfaceinfomanager-service;1" +%} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl new file mode 100644 index 00000000..8918daa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl @@ -0,0 +1,100 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the external XPT loader interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsISupports.idl" +#include "nsILocalFile.idl" +#include "nsIInputStream.idl" + +/** + * Implement nsIXPTLoaderSink if you want to enumerate the entries in + * an XPT archive of some kind + */ +[scriptable, uuid(6E48C500-8682-4730-ADD6-7DB693B9E7BA)] +interface nsIXPTLoaderSink : nsISupports { + + /** + * called by the loader for each entry in the archive + * @param itemName the name of this particular item in the archive + * @param index the index of the item inthe archive + * @param stream contains the contents of the xpt file + */ + void foundEntry(in string itemName, + in long index, + in nsIInputStream xptData); +}; + +/** + * The XPT loader interface: implemented by a loader to grab an input + * stream which will be consumed by the interface loader. + */ +[scriptable, uuid(368A15D9-17A9-4c2b-AC3D-A35B3A22B876)] +interface nsIXPTLoader : nsISupports { + /** + * enumerate entries in the given archive + * for each entry found, the loader will call the sink's + * foundEntry() method with the appropriate information and a + * stream that the consumer can read from + * @param file the file to read from + * @param sink an object which will be called with each file found + * in the file + */ + void enumerateEntries(in nsILocalFile file, + in nsIXPTLoaderSink sink ); + + /** + * Load a specific entry from the archive + * @param file the file to read from + * @param name the name of the xpt within the file + * @return an input stream that will read the raw xpt data from + * the file + */ + nsIInputStream loadEntry(in nsILocalFile file, + in string name); +}; + + +%{C++ + +// the first part of the contractID for any loader +// append the type of loader that you need, such as "zip" +#define NS_XPTLOADER_CONTRACTID_PREFIX \ + "@mozilla.org/xptinfo/loader;1&type=" + +%} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h new file mode 100644 index 00000000..076482a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* XPTI_PUBLIC_API and XPTI_GetInterfaceInfoManager declarations. */ + +#ifndef xptiinfo_h___ +#define xptiinfo_h___ + +#include "prtypes.h" +#include "xpt_struct.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPTI_GetInterfaceInfoManager VBoxNsxpXPTI_GetInterfaceInfoManager +#define XPTI_FreeInterfaceInfoManager VBoxNsxpXPTI_FreeInterfaceInfoManager +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* + * The linkage of XPTI API functions differs depending on whether the file is + * used within the XPTI library or not. Any source file within the XPTI + * library should define EXPORT_XPTI_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPTI_API +#define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPTI_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#if defined(_WIN32) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2_VACPP) +# define XPTI_EXPORT extern +#else +# define XPTI_EXPORT +#endif +#else +#if defined(_WIN32) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2_VACPP) +# define XPTI_PUBLIC_API(t) extern t +# define XPTI_PUBLIC_DATA(t) extern t +# define XPTI_EXPORT extern +#else +# define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPTI_PUBLIC_DATA(t) t +# define XPTI_EXPORT +#endif +#endif +#define XPTI_FRIEND_API(t) XPTI_PUBLIC_API(t) +#define XPTI_FRIEND_DATA(t) XPTI_PUBLIC_DATA(t) + +class nsIInterfaceInfoManager; +PR_BEGIN_EXTERN_C +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager(); + +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager(); +PR_END_EXTERN_C + + + +// Flyweight wrapper classes for xpt_struct.h structs. +// Everything here is dependent upon - and sensitive to changes in - +// xpcom/typelib/xpt/public/xpt_struct.h! + +class nsXPTType : public XPTTypeDescriptorPrefix +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTType() + {} // random contents + nsXPTType(const XPTTypeDescriptorPrefix& prefix) + {*(XPTTypeDescriptorPrefix*)this = prefix;} + + nsXPTType(const uint8& prefix) + {*(uint8*)this = prefix;} + + nsXPTType& operator=(uint8 val) + {flags = val; return *this;} + + nsXPTType& operator=(const nsXPTType& other) + {flags = other.flags; return *this;} + + operator uint8() const + {return flags;} + + PRBool IsPointer() const + {return 0 != (XPT_TDP_IS_POINTER(flags));} + + PRBool IsUniquePointer() const + {return 0 != (XPT_TDP_IS_UNIQUE_POINTER(flags));} + + PRBool IsReference() const + {return 0 != (XPT_TDP_IS_REFERENCE(flags));} + + PRBool IsArithmetic() const // terminology from Harbison/Steele + {return flags <= T_WCHAR;} + + PRBool IsInterfacePointer() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE: + case T_INTERFACE_IS: + return PR_TRUE; + } + } + + PRBool IsArray() const + {return (PRBool) TagPart() == T_ARRAY;} + + // 'Dependent' means that params of this type are dependent upon other + // params. e.g. an T_INTERFACE_IS is dependent upon some other param at + // runtime to say what the interface type of this param really is. + PRBool IsDependent() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE_IS: + case TD_ARRAY: + case T_PSTRING_SIZE_IS: + case T_PWSTRING_SIZE_IS: + return PR_TRUE; + } + } + + uint8 TagPart() const + {return (uint8) (flags & XPT_TDP_TAGMASK);} + + enum + { + T_I8 = TD_INT8 , + T_I16 = TD_INT16 , + T_I32 = TD_INT32 , + T_I64 = TD_INT64 , + T_U8 = TD_UINT8 , + T_U16 = TD_UINT16 , + T_U32 = TD_UINT32 , + T_U64 = TD_UINT64 , + T_FLOAT = TD_FLOAT , + T_DOUBLE = TD_DOUBLE , + T_BOOL = TD_BOOL , + T_CHAR = TD_CHAR , + T_WCHAR = TD_WCHAR , + T_VOID = TD_VOID , + T_IID = TD_PNSIID , + T_DOMSTRING = TD_DOMSTRING , + T_CHAR_STR = TD_PSTRING , + T_WCHAR_STR = TD_PWSTRING , + T_INTERFACE = TD_INTERFACE_TYPE , + T_INTERFACE_IS = TD_INTERFACE_IS_TYPE, + T_ARRAY = TD_ARRAY , + T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS , + T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS , + T_UTF8STRING = TD_UTF8STRING , + T_CSTRING = TD_CSTRING , + T_ASTRING = TD_ASTRING + }; +// NO DATA - this a flyweight wrapper +}; + +class nsXPTParamInfo : public XPTParamDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTParamInfo(const XPTParamDescriptor& desc) + {*(XPTParamDescriptor*)this = desc;} + + + PRBool IsIn() const {return 0 != (XPT_PD_IS_IN(flags));} + PRBool IsOut() const {return 0 != (XPT_PD_IS_OUT(flags));} + PRBool IsRetval() const {return 0 != (XPT_PD_IS_RETVAL(flags));} + PRBool IsShared() const {return 0 != (XPT_PD_IS_SHARED(flags));} + PRBool IsDipper() const {return 0 != (XPT_PD_IS_DIPPER(flags));} + const nsXPTType GetType() const {return type.prefix;} + + // NOTE: other activities on types are done via methods on nsIInterfaceInfo + +private: + nsXPTParamInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +class nsXPTMethodInfo : public XPTMethodDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTMethodInfo(const XPTMethodDescriptor& desc) + {*(XPTMethodDescriptor*)this = desc;} + + PRBool IsGetter() const {return 0 != (XPT_MD_IS_GETTER(flags) );} + PRBool IsSetter() const {return 0 != (XPT_MD_IS_SETTER(flags) );} + PRBool IsNotXPCOM() const {return 0 != (XPT_MD_IS_NOTXPCOM(flags));} + PRBool IsConstructor() const {return 0 != (XPT_MD_IS_CTOR(flags) );} + PRBool IsHidden() const {return 0 != (XPT_MD_IS_HIDDEN(flags) );} + const char* GetName() const {return name;} + uint8 GetParamCount() const {return num_args;} + /* idx was index before I got _sick_ of the warnings on Unix, sorry jband */ + const nsXPTParamInfo GetParam(uint8 idx) const + { + NS_PRECONDITION(idx < GetParamCount(),"bad arg"); + return params[idx]; + } + const nsXPTParamInfo GetResult() const + {return *result;} +private: + nsXPTMethodInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + + +// forward declaration +struct nsXPTCMiniVariant; + +class nsXPTConstant : public XPTConstDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTConstant(const XPTConstDescriptor& desc) + {*(XPTConstDescriptor*)this = desc;} + + const char* GetName() const + {return name;} + + const nsXPTType GetType() const + {return type.prefix;} + + // XXX this is ugly. But sometimes you gotta do what you gotta do. + // A reinterpret_cast won't do the trick here. And this plain C cast + // works correctly and is safe enough. + // See http://bugzilla.mozilla.org/show_bug.cgi?id=49641 + const nsXPTCMiniVariant* GetValue() const + {return (nsXPTCMiniVariant*) &value;} +private: + nsXPTConstant(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +#endif /* xptiinfo_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in new file mode 100644 index 00000000..de5fd9b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla 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/MPL/ +# +# 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 the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptinfo +REQUIRES = \ + string \ + $(NULL) + +CPPSRCS = \ + xptiFile.cpp \ + xptiInterfaceInfo.cpp \ + xptiInterfaceInfoManager.cpp \ + xptiManifest.cpp \ + xptiMisc.cpp \ + xptiTypelibGuts.cpp \ + xptiWorkingSet.cpp \ + xptiZipItem.cpp \ + xptiZipLoader.cpp \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +# For nsManifestLineReader class. +LOCAL_INCLUDES = -I$(srcdir)/../../../ds + +DEFINES += -DEXPORT_XPTI_API -DEXPORT_XPT_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO new file mode 100644 index 00000000..c5bb1c64 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO @@ -0,0 +1,20 @@ +/* jband - 03/24/00 - */ + +- DOCS +- improve error handling + - should some errors really be warnings? + - should autoreg support additional channel to recieve warnings so that + an installer can decide whether or not to accept the consequences of + leaving the newly installed files in place? +- verification of interfaces (warnings and/or errors) + - verify that repeated interfaces are identical in all ways + - verify that interface names are always one-to-one with iids +- check for truncated xpt files and version problems + - http://bugzilla.mozilla.org/show_bug.cgi?id=33193 +- TESTS! + - e.g. verify the merge stuff really works for various inputs. + - we really need a set of .xpt and .zip files and code that does an array + of autoreg and interfaceinof use activitities to test various corners + of the system. +- better autoreg logging +- use only 32 bits for file size? diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp new file mode 100644 index 00000000..50362c75 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiFile. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiFile) + +xptiFile::xptiFile() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mSize(), + mDate(), + mName(nsnull), + mGuts(nsnull), + mDirectory(0) +{ + // empty + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(aSize), + mDate(aDate), + mName(aName), + mGuts(nsnull), + mDirectory(aDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(r.mSize), + mDate(r.mDate), + mName(nsnull), + mGuts(nsnull), + mDirectory(r.mDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::~xptiFile() +{ + MOZ_COUNT_DTOR(xptiFile); +} + +PRBool +xptiFile::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp new file mode 100644 index 00000000..69bf86df --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */ + +#include "xptiprivate.h" + +/***************************************************************************/ +// Debug Instrumentation... + +#ifdef SHOW_INFO_COUNT_STATS +static int DEBUG_TotalInfos = 0; +static int DEBUG_CurrentInfos = 0; +static int DEBUG_MaxInfos = 0; +static int DEBUG_MonitorEntryCount = 0; + +#define LOG_INFO_CREATE(t) \ + DEBUG_TotalInfos++; \ + DEBUG_CurrentInfos++; \ + if(DEBUG_MaxInfos < DEBUG_CurrentInfos) \ + DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */ + +#define LOG_INFO_DESTROY(t) \ + DEBUG_CurrentInfos-- /* no ';' */ + +#define LOG_INFO_MONITOR_ENTRY \ + DEBUG_MonitorEntryCount++ /* no ';' */ + +#else /* SHOW_INFO_COUNT_STATS */ + +#define LOG_INFO_CREATE(t) ((void)0) +#define LOG_INFO_DESTROY(t) ((void)0) +#define LOG_INFO_MONITOR_ENTRY ((void)0) +#endif /* SHOW_INFO_COUNT_STATS */ + +#ifdef DEBUG +// static +void xptiInterfaceInfo::DEBUG_ShutdownNotification() +{ +#ifdef SHOW_INFO_COUNT_STATS + printf("iiii %d total xptiInterfaceInfos created\n", DEBUG_TotalInfos); + printf("iiii %d max xptiInterfaceInfos alive at one time\n", DEBUG_MaxInfos); + printf("iiii %d xptiInterfaceInfos still alive\n", DEBUG_CurrentInfos); + printf("iiii %d times locked\n", DEBUG_MonitorEntryCount); +#endif +} +#endif /* DEBUG */ + +/***************************************************************************/ + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(name, nameLength, iid, typelib); +} + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + size_t nameLength = PL_strlen(r.mName); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(r, nameLength, typelib); +} + + +xptiInterfaceEntry::xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib) + : mIID(iid), + mTypelib(typelib), + mInfo(nsnull), + mFlags(uint8(0)) +{ + memcpy(mName, name, nameLength); +} + +xptiInterfaceEntry::xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib) + : mIID(r.mIID), + mTypelib(typelib), + mInfo(nsnull), + mFlags(r.mFlags) +{ + SetResolvedState(NOT_RESOLVED); + memcpy(mName, r.mName, nameLength); +} + +PRBool +xptiInterfaceEntry::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + nsAutoLock lock(xptiInterfaceInfoManager::GetResolveLock()); + return ResolveLocked(aWorkingSet); +} + +PRBool +xptiInterfaceEntry::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + int resolvedState = GetResolveState(); + + if(resolvedState == FULLY_RESOLVED) + return PR_TRUE; + if(resolvedState == RESOLVE_FAILED) + return PR_FALSE; + + xptiInterfaceInfoManager* mgr = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + + if(!mgr) + return PR_FALSE; + + if(!aWorkingSet) + { + aWorkingSet = mgr->GetWorkingSet(); + } + + if(resolvedState == NOT_RESOLVED) + { + LOG_RESOLVE(("! begin resolve of %s\n", mName)); + // Make a copy of mTypelib because the underlying memory will change! + xptiTypelib typelib = mTypelib; + + // We expect our PartiallyResolveLocked() to get called before + // this returns. + if(!mgr->LoadFile(typelib, aWorkingSet)) + { + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + // The state was changed by LoadFile to PARTIALLY_RESOLVED, so this + // ...falls through... + } + + NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!"); + + // 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) + { + xptiInterfaceEntry* parent = + aWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(parent_index - 1); + + if(!parent || !parent->EnsureResolvedLocked()) + { + xptiTypelib aTypelib = mInterface->mTypelib; + mInterface = nsnull; + mTypelib = aTypelib; + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + + mInterface->mParent = parent; + + mInterface->mMethodBaseIndex = + parent->mInterface->mMethodBaseIndex + + parent->mInterface->mDescriptor->num_methods; + + mInterface->mConstantBaseIndex = + parent->mInterface->mConstantBaseIndex + + parent->mInterface->mDescriptor->num_constants; + + } + LOG_RESOLVE(("+ complete resolve of %s\n", mName)); + + SetResolvedState(FULLY_RESOLVED); + return PR_TRUE; +} + +// This *only* gets called by xptiInterfaceInfoManager::LoadFile (while locked). +PRBool +xptiInterfaceEntry::PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state"); + + LOG_RESOLVE(("~ partial resolve of %s\n", mName)); + + xptiInterfaceGuts* iface = + xptiInterfaceGuts::NewGuts(aDescriptor, mTypelib, aWorkingSet); + + if(!iface) + return PR_FALSE; + + mInterface = iface; + +#ifdef DEBUG + if(!DEBUG_ScriptableFlagIsValid()) + { + NS_ERROR("unexpected scriptable flag!"); + SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)); + } +#endif + + SetResolvedState(PARTIALLY_RESOLVED); + return PR_TRUE; +} + +/**************************************************/ +// These non-virtual methods handle the delegated nsIInterfaceInfo methods. + +nsresult +xptiInterfaceEntry::GetName(char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1); + return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::GetIID(nsIID **iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID)); + return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::IsScriptable(PRBool* result) +{ + // It is not necessary to Resolve because this info is read from manifest. + NS_ASSERTION(DEBUG_ScriptableFlagIsValid(), "scriptable flag out of sync!"); + *result = GetScriptableFlag(); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::IsFunction(PRBool* result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *result = XPT_ID_IS_FUNCTION(GetInterfaceGuts()->mDescriptor->flags); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetConstantCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) +{ + 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_ERROR("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; +} + +nsresult +xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16 *index, + const nsXPTMethodInfo** result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + // This is a slow algorithm, but this is not expected to be called much. + for(uint16 i = 0; i < mInterface->mDescriptor->num_methods; ++i) + { + const nsXPTMethodInfo* info; + info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[i]); + if (PL_strcmp(methodName, info->GetName()) == 0) { + *index = i + mInterface->mMethodBaseIndex; + *result = info; + return NS_OK; + } + } + + if(mInterface->mParent) + return mInterface->mParent->GetMethodInfoForName(methodName, index, result); + else + { + *index = 0; + *result = 0; + return NS_ERROR_INVALID_ARG; + } +} + +nsresult +xptiInterfaceEntry::GetConstant(uint16 index, const nsXPTConstant** constant) +{ + 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; +} + +// this is a private helper + +nsresult +xptiInterfaceEntry::GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetEntryForParam(methodIndex, param, entry); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad param"); + 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_ERROR("not an interface"); + return NS_ERROR_INVALID_ARG; + } + + xptiInterfaceEntry* theEntry = + mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(td->type.iface - 1); + + // This can happen if a declared interface is not available at runtime. + if(!theEntry) + { + NS_WARNING("Declared InterfaceInfo not found"); + *entry = nsnull; + return NS_ERROR_FAILURE; + } + + *entry = theEntry; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInfoForParam(uint16 methodIndex, + const nsXPTParamInfo *param, + nsIInterfaceInfo** info) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + + xptiInterfaceInfo* theInfo; + rv = entry->GetInterfaceInfo(&theInfo); + if(NS_FAILED(rv)) + return rv; + + *info = NS_STATIC_CAST(nsIInterfaceInfo*, theInfo); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetIIDForParam(uint16 methodIndex, + const nsXPTParamInfo* param, nsIID** iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + return entry->GetIID(iid); +} + +nsresult +xptiInterfaceEntry::GetIIDForParamNoAlloc(PRUint16 methodIndex, + const nsXPTParamInfo * param, + nsIID *iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + *iid = entry->mIID; + return NS_OK; +} + +// this is a private helper +nsresult +xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type) +{ + 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_ERROR("bad dimension"); + return NS_ERROR_INVALID_ARG; + } + td = &additional_types[td->type.additional_type]; + } + + *type = td; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + nsXPTType* type) +{ + 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_ERROR("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; +} + +nsresult +xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + 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_ERROR("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_ERROR("not a size_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetLengthIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + 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_ERROR("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_ERROR("not a length_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum2; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint8* argnum) +{ + 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_ERROR("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_ERROR("not an iid_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +/* PRBool isIID (in nsIIDPtr IID); */ +nsresult +xptiInterfaceEntry::IsIID(const nsIID * IID, PRBool *_retval) +{ + // It is not necessary to Resolve because this info is read from manifest. + *_retval = mIID.Equals(*IID); + return NS_OK; +} + +/* void getNameShared ([shared, retval] out string name); */ +nsresult +xptiInterfaceEntry::GetNameShared(const char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = mName; + return NS_OK; +} + +/* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */ +nsresult +xptiInterfaceEntry::GetIIDShared(const nsIID * *iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = &mIID; + return NS_OK; +} + +/* PRBool hasAncestor (in nsIIDPtr iid); */ +nsresult +xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval) +{ + *_retval = PR_FALSE; + + for(xptiInterfaceEntry* current = this; + current; + current = current->mInterface->mParent) + { + if(current->mIID.Equals(*iid)) + { + *_retval = PR_TRUE; + break; + } + if(!current->EnsureResolved()) + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +/***************************************************/ + +nsresult +xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info) +{ + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + +#ifdef SHOW_INFO_COUNT_STATS + static int callCount = 0; + if(!(++callCount%100)) + printf("iiii %d xptiInterfaceInfos currently alive\n", DEBUG_CurrentInfos); +#endif + + if(!mInfo) + { + mInfo = new xptiInterfaceInfo(this); + if(!mInfo) + { + *info = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_ADDREF(*info = mInfo); + return NS_OK; +} + +void +xptiInterfaceEntry::LockedInvalidateInterfaceInfo() +{ + if(mInfo) + { + mInfo->Invalidate(); + mInfo = nsnull; + } +} + +/***************************************************************************/ + +NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo) + +xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry) + : mEntry(entry), mParent(nsnull) +{ + LOG_INFO_CREATE(this); +} + +xptiInterfaceInfo::~xptiInterfaceInfo() +{ + LOG_INFO_DESTROY(this); + NS_IF_RELEASE(mParent); + NS_ASSERTION(!mEntry, "bad state in dtor"); +} + +nsrefcnt +xptiInterfaceInfo::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this)); + return cnt; +} + +nsrefcnt +xptiInterfaceInfo::Release(void) +{ + xptiInterfaceEntry* entry = mEntry; + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); + NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo"); + if(!cnt) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + + // If GetInterfaceInfo added and *released* a reference before we + // acquired the monitor then 'this' might already be dead. In that + // case we would not want to try to access any instance data. We + // would want to bail immediately. If 'this' is already dead then the + // entry will no longer have a pointer to 'this'. So, we can protect + // ourselves from danger without more aggressive locking. + if(entry && !entry->InterfaceInfoEquals(this)) + return 0; + + // If GetInterfaceInfo added a reference before we acquired the monitor + // then we want to bail out of here without destorying the object. + if(mRefCnt) + return 1; + + if(mEntry) + { + mEntry->LockedInterfaceInfoDeathNotification(); + mEntry = nsnull; + } + + NS_DELETEXPCOM(this); + return 0; + } + return cnt; +} + +/***************************************************************************/ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp new file mode 100644 index 00000000..5ae06914 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -0,0 +1,2126 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiInterfaceInfoManager. */ + +#include "xptiprivate.h" +#include "nsDependentString.h" +#include "nsString.h" + +#define NS_ZIPLOADER_CONTRACTID NS_XPTLOADER_CONTRACTID_PREFIX "zip" + +NS_IMPL_THREADSAFE_ISUPPORTS2(xptiInterfaceInfoManager, + nsIInterfaceInfoManager, + nsIInterfaceInfoSuperManager) + +static xptiInterfaceInfoManager* gInterfaceInfoManager = nsnull; +#ifdef DEBUG +static int gCallCount = 0; +#endif + +// static +xptiInterfaceInfoManager* +xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef() +{ + if(!gInterfaceInfoManager) + { + nsCOMPtr searchPath; + BuildFileSearchPath(getter_AddRefs(searchPath)); + if(!searchPath) + { + NS_ERROR("can't get xpt search path!"); + return nsnull; + } + + gInterfaceInfoManager = new xptiInterfaceInfoManager(searchPath); + if(gInterfaceInfoManager) + NS_ADDREF(gInterfaceInfoManager); + if(!gInterfaceInfoManager->IsValid()) + { + NS_RELEASE(gInterfaceInfoManager); + } + else + { + PRBool mustAutoReg = + !xptiManifest::Read(gInterfaceInfoManager, + &gInterfaceInfoManager->mWorkingSet); +#ifdef DEBUG + { + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(gInterfaceInfoManager, + gInterfaceInfoManager->mAutoRegLogFile, PR_TRUE); + LOG_AUTOREG(("debug build forced autoreg after %s load of manifest\n", mustAutoReg ? "FAILED" : "successful")); + + mustAutoReg = PR_TRUE; + } +#endif // DEBUG + if(mustAutoReg) + gInterfaceInfoManager->AutoRegisterInterfaces(); + } + } + return gInterfaceInfoManager; +} + +void +xptiInterfaceInfoManager::FreeInterfaceInfoManager() +{ + if(gInterfaceInfoManager) + gInterfaceInfoManager->LogStats(); + + NS_IF_RELEASE(gInterfaceInfoManager); +} + +PRBool +xptiInterfaceInfoManager::IsValid() +{ + return mWorkingSet.IsValid() && + mResolveLock && + mAutoRegLock && + mInfoMonitor && + mAdditionalManagersLock; +} + +xptiInterfaceInfoManager::xptiInterfaceInfoManager(nsISupportsArray* aSearchPath) + : mWorkingSet(aSearchPath), + mOpenLogFile(nsnull), + mResolveLock(PR_NewLock()), + mAutoRegLock(PR_NewLock()), + mInfoMonitor(nsAutoMonitor::NewMonitor("xptiInfoMonitor")), + mAdditionalManagersLock(PR_NewLock()), + mSearchPath(aSearchPath) +{ + const char* statsFilename = PR_GetEnv("MOZILLA_XPTI_STATS"); + if(statsFilename) + { + mStatsLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mStatsLogFile && + NS_SUCCEEDED(mStatsLogFile->InitWithNativePath(nsDependentCString(statsFilename)))) + { + printf("* Logging xptinfo stats to: %s\n", statsFilename); + } + else + { + printf("* Failed to create xptinfo stats file: %s\n", statsFilename); + mStatsLogFile = nsnull; + } + } + + const char* autoRegFilename = PR_GetEnv("MOZILLA_XPTI_REGLOG"); + if(autoRegFilename) + { + mAutoRegLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mAutoRegLogFile && + NS_SUCCEEDED(mAutoRegLogFile->InitWithNativePath(nsDependentCString(autoRegFilename)))) + { + printf("* Logging xptinfo autoreg to: %s\n", autoRegFilename); + } + else + { + printf("* Failed to create xptinfo autoreg file: %s\n", autoRegFilename); + mAutoRegLogFile = nsnull; + } + } +} + +xptiInterfaceInfoManager::~xptiInterfaceInfoManager() +{ + // We only do this on shutdown of the service. + mWorkingSet.InvalidateInterfaceInfos(); + + if(mResolveLock) + PR_DestroyLock(mResolveLock); + if(mAutoRegLock) + PR_DestroyLock(mAutoRegLock); + if(mInfoMonitor) + nsAutoMonitor::DestroyMonitor(mInfoMonitor); + if(mAdditionalManagersLock) + PR_DestroyLock(mAdditionalManagersLock); + + gInterfaceInfoManager = nsnull; +#ifdef DEBUG + xptiInterfaceInfo::DEBUG_ShutdownNotification(); + gCallCount = 0; +#endif +} + +static nsresult +GetDirectoryFromDirService(const char* codename, nsILocalFile** aDir) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aDir,"loser!"); + + nsresult rv; + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + return dirService->Get(codename, NS_GET_IID(nsILocalFile), (void**) aDir); +} + +static PRBool +AppendFromDirServiceList(const char* codename, nsISupportsArray* aPath) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aPath,"loser!"); + + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if(!dirService) + return PR_FALSE; + + nsCOMPtr fileList; + dirService->Get(codename, NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(fileList)); + if(!fileList) + return PR_FALSE; + + PRBool more; + while(NS_SUCCEEDED(fileList->HasMoreElements(&more)) && more) + { + nsCOMPtr dir; + fileList->GetNext(getter_AddRefs(dir)); + if(!dir || !aPath->AppendElement(dir)) + return PR_FALSE; + } + + return PR_TRUE; +} + +// static +PRBool xptiInterfaceInfoManager::BuildFileSearchPath(nsISupportsArray** aPath) +{ +#ifdef DEBUG + NS_ASSERTION(!gCallCount++, "Expected only one call!"); +#endif + + nsCOMPtr searchPath; + NS_NewISupportsArray(getter_AddRefs(searchPath)); + if(!searchPath) + return PR_FALSE; + + nsCOMPtr compDir; + + // Always put components directory first + + if(NS_FAILED(GetDirectoryFromDirService(NS_XPCOM_COMPONENT_DIR, + getter_AddRefs(compDir))) || + !searchPath->AppendElement(compDir)) + { + return PR_FALSE; + } + + // Add additional plugins dirs + // No error checking here since this is optional in some embeddings + + // Add the GRE's component directory to searchPath if the + // application is using an GRE. + // An application indicates that it's using an GRE by returning + // a valid nsIFile via it's directory service provider interface. + // + // Please see http://www.mozilla.org/projects/embedding/MRE.html + // for more info. on GREs + // + nsCOMPtr greComponentDirectory; + nsresult rv = GetDirectoryFromDirService(NS_GRE_COMPONENT_DIR, + getter_AddRefs(greComponentDirectory)); + if(NS_SUCCEEDED(rv) && greComponentDirectory) + { + // make sure we only append a directory if its a different one + PRBool equalsCompDir = PR_FALSE; + greComponentDirectory->Equals(compDir, &equalsCompDir); + + if(!equalsCompDir) + searchPath->AppendElement(greComponentDirectory); + } + + (void)AppendFromDirServiceList(NS_XPCOM_COMPONENT_DIR_LIST, searchPath); + (void)AppendFromDirServiceList(NS_APP_PLUGINS_DIR_LIST, searchPath); + + NS_ADDREF(*aPath = searchPath); + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetCloneOfManifestLocation(nsILocalFile** aFile) +{ + // We *trust* that this will not change! + nsCOMPtr lf; + nsresult rv = GetDirectoryFromDirService(NS_XPCOM_XPTI_REGISTRY_FILE, + getter_AddRefs(lf)); + + if (NS_FAILED(rv)) return PR_FALSE; + + rv = xptiCloneLocalFile(lf, aFile); + if (NS_FAILED(rv)) return PR_FALSE; + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetApplicationDir(nsILocalFile** aDir) +{ + // We *trust* that this will not change! + return NS_SUCCEEDED(GetDirectoryFromDirService(NS_XPCOM_CURRENT_PROCESS_DIR, aDir)); +} + +PRBool +xptiInterfaceInfoManager::BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList) +{ + NS_ASSERTION(aFileList, "loser!"); + + nsresult rv; + + nsCOMPtr fileList = + do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID); + if(!fileList) + return PR_FALSE; + + PRUint32 pathCount; + if(NS_FAILED(aSearchPath->Count(&pathCount))) + return PR_FALSE; + + for(PRUint32 i = 0; i < pathCount; i++) + { + nsCOMPtr dir; + rv = xptiCloneElementAsLocalFile(aSearchPath, i, getter_AddRefs(dir)); + if(NS_FAILED(rv) || !dir) + return PR_FALSE; + + nsCOMPtr entries; + rv = dir->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + continue; + + 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; + + PRBool isFile; + if(NS_FAILED(file->IsFile(&isFile)) || !isFile) + { + continue; + } + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + if(xptiFileType::IsUnknown(name.get())) + continue; + + LOG_AUTOREG(("found file: %s\n", name.get())); + + if(!fileList->InsertElementAt(file, count)) + return PR_FALSE; + ++count; + } + } + + NS_ADDREF(*aFileList = fileList); + return PR_TRUE; +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFile(nsILocalFile* aFile, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFile, "loser!"); + + XPTHeader *header = nsnull; + char *whole = nsnull; + PRFileDesc* fd = nsnull; + XPTState *state = nsnull; + XPTCursor cursor; + PRInt32 flen; + PRInt64 fileSize; + + PRBool saveFollowLinks; + aFile->GetFollowLinks(&saveFollowLinks); + aFile->SetFollowLinks(PR_TRUE); + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + whole = new char[flen]; + if (!whole) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + // all exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + { + goto out; + } + + if(flen > PR_Read(fd, whole, flen)) + { + 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)) + { + header = nsnull; + goto out; + } + + out: + if(fd) + PR_Close(fd); + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + aFile->SetFollowLinks(saveFollowLinks); + 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(NS_FAILED(aWorkingSet->GetCloneOfDirectoryAt(fileRecord->GetDirectory(), + getter_AddRefs(file))) || !file) + return PR_FALSE; + + if(NS_FAILED(file->AppendNative(nsDependentCString(fileRecord->GetName())))) + return PR_FALSE; + + XPTHeader* header; + + if(aTypelibRecord.IsZip()) + { + zipItem = &aWorkingSet->GetZipItemAt(aTypelibRecord.GetZipItemIndex()); + + // See the big comment below in the 'non-zip' case... + if(zipItem->GetGuts()) + { + NS_ERROR("Trying to load an xpt file from a zip twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("# loading zip item %s::%s\n", fileRecord->GetName(), zipItem->GetName())); + + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr stream; + rv = loader->LoadEntry(file, zipItem->GetName(), + getter_AddRefs(stream)); + + if (NS_FAILED(rv)) + return PR_FALSE; + + header = + xptiZipLoader::ReadXPTFileFromInputStream(stream, aWorkingSet); + } else { + header = nsnull; + NS_WARNING("Could not load XPT Zip loader"); + } + } + else + { + // The file would only have guts already if we previously failed to + // find an interface info in a file where the manifest claimed it was + // going to be. + // + // Normally, when the file gets loaded (and the guts set) then all + // interfaces would also be resolved. So, if we are here again for + // the same file then there must have been some interface that was + // expected but not present. Now we are explicitly trying to find it + // and it isn't going to be there this time either. + // + // This is an assertion style error in a DEBUG build because it shows + // that we failed to detect this in autoreg. For release builds (where + // autoreg is not run on every startup) it is just bad. But by returning + // PR_FALSE we mark this interface as RESOLVE_FAILED and get on with + // things without crashing or anything. + // + // We don't want to do an autoreg here because this is too much of an + // edge case (and in that odd case it might autoreg multiple times if + // many interfaces had been removed). But, by deleting the manifest we + // force the system to get it right on the next run. + + if(fileRecord->GetGuts()) + { + NS_ERROR("Trying to load an xpt file twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("^ 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, aWorkingSet)) + return PR_FALSE; + } + else + { + // This also allocs fileRecord.GetGuts() used below. + if(!fileRecord->SetHeader(header, aWorkingSet)) + 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; + + xptiHashEntry* hashEntry; + + if(!iface->iid.Equals(zeroIID)) + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + &iface->iid, PL_DHASH_LOOKUP); + } + else + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + iface->name, PL_DHASH_LOOKUP); + } + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + // This one is just not resolved anywhere! + continue; + } + + if(aTypelibRecord.IsZip()) + zipItem->GetGuts()->SetEntryAt(i, entry); + else + fileRecord->GetGuts()->SetEntryAt(i, entry); + + XPTInterfaceDescriptor* descriptor = iface->interface_descriptor; + + if(descriptor && aTypelibRecord.Equals(entry->GetTypelibRecord())) + entry->PartiallyResolveLocked(descriptor, aWorkingSet); + } + return PR_TRUE; +} + +static int +IndexOfFileWithName(const char* aName, const xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aName, "loser!"); + + for(PRUint32 i = 0; i < aWorkingSet->GetFileCount(); ++i) + { + if(0 == PL_strcmp(aName, aWorkingSet->GetFileAt(i).GetName())) + return i; + } + return -1; +} + +static int +IndexOfDirectoryOfFile(nsISupportsArray* aSearchPath, nsILocalFile* aFile) +{ + nsCOMPtr parent; + aFile->GetParent(getter_AddRefs(parent)); + if(parent) + { + PRUint32 count = 0; + aSearchPath->Count(&count); + NS_ASSERTION(count, "broken search path! bad count"); + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr current; + aSearchPath->QueryElementAt(i, NS_GET_IID(nsIFile), + getter_AddRefs(current)); + NS_ASSERTION(current, "broken search path! bad element"); + PRBool same; + if(NS_SUCCEEDED(parent->Equals(current, &same)) && same) + return (int) i; + } + } + NS_ERROR("file not in search directory!"); + return -1; +} + +struct SortData +{ + nsISupportsArray* mSearchPath; + xptiWorkingSet* mWorkingSet; +}; + +PR_STATIC_CALLBACK(int) +xptiSortFileList(const void * p1, const void *p2, void * closure) +{ + nsILocalFile* pFile1 = *((nsILocalFile**) p1); + nsILocalFile* pFile2 = *((nsILocalFile**) p2); + SortData* data = (SortData*) closure; + + nsCAutoString name1; + nsCAutoString name2; + + if(NS_FAILED(pFile1->GetNativeLeafName(name1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetNativeLeafName(name2))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + + int index1 = IndexOfFileWithName(name1.get(), data->mWorkingSet); + int index2 = IndexOfFileWithName(name2.get(), data->mWorkingSet); + + // Get these now in case we need them later. + PRBool isXPT1 = xptiFileType::IsXPT(name1.get()); + PRBool isXPT2 = xptiFileType::IsXPT(name2.get()); + int nameOrder = Compare(name1, name2); + + // both in workingSet, preserve old order + if(index1 != -1 && index2 != -1) + return index1 - index2; + + if(index1 != -1) + return 1; + + if(index2 != -1) + return -1; + + // neither is in workingset + + // check how they compare in search path order + + int dirIndex1 = IndexOfDirectoryOfFile(data->mSearchPath, pFile1); + int dirIndex2 = IndexOfDirectoryOfFile(data->mSearchPath, pFile2); + + if(dirIndex1 != dirIndex2) + return dirIndex1 - dirIndex2; + + // .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 and in + // the same directory, sort by size + + PRInt64 size1; + PRInt64 size2; + + if(NS_FAILED(pFile1->GetFileSize(&size1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetFileSize(&size2))) + { + NS_ERROR("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; +} + +nsILocalFile** +xptiInterfaceInfoManager::BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + // 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 = nsnull; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList)) || + 0 == countOfFilesInFileList) + return nsnull; + + orderedFileList = (nsILocalFile**) + XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(nsILocalFile*) * countOfFilesInFileList); + + if(!orderedFileList) + return nsnull; + + // fill our list for sorting + for(i = 0; i < countOfFilesInFileList; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + // Intentionally NOT addref'd cuz we know these are pinned in aFileList. + orderedFileList[i] = file.get(); + } + + // sort the filelist + + SortData sortData = {aSearchPath, aWorkingSet}; + NS_QuickSort(orderedFileList, countOfFilesInFileList, sizeof(nsILocalFile*), + xptiSortFileList, &sortData); + + return orderedFileList; +} + +xptiInterfaceInfoManager::AutoRegMode +xptiInterfaceInfoManager::DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + PRUint32 countOfFilesInWorkingSet = aWorkingSet->GetFileCount(); + PRUint32 countOfFilesInFileList; + PRUint32 i; + PRUint32 k; + + if(0 == countOfFilesInWorkingSet) + { + // Loading manifest might have failed. Better safe... + return FULL_VALIDATION_REQUIRED; + } + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + if(countOfFilesInFileList == countOfFilesInWorkingSet) + { + // try to determine if *no* files are new or changed. + + PRBool same = PR_TRUE; + for(i = 0; i < countOfFilesInFileList && same; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + PRInt64 size; + PRInt64 date; + nsCAutoString name; + PRUint32 directory; + + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &directory)) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + for(k = 0; k < countOfFilesInWorkingSet; ++k) + { + xptiFile& target = aWorkingSet->GetFileAt(k); + + if(directory == target.GetDirectory() && + name.Equals(target.GetName())) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the workingset? + if(k == countOfFilesInWorkingSet) + same = PR_FALSE; + } + if(same) + return NO_FILES_CHANGED; + } + else if(countOfFilesInFileList > countOfFilesInWorkingSet) + { + // try to determine if the only changes are additional new files + // XXX Wimping out and doing this as a separate walk through the lists. + + PRBool same = PR_TRUE; + + for(i = 0; i < countOfFilesInWorkingSet && same; ++i) + { + xptiFile& target = aWorkingSet->GetFileAt(i); + + for(k = 0; k < countOfFilesInFileList; ++k) + { + nsCOMPtr file; + aFileList->QueryElementAt(k, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + PRBool sameName = name.Equals(target.GetName()); + if(sameName) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the file list? + if(k == countOfFilesInFileList) + same = PR_FALSE; + } + if(same) + return FILES_ADDED_ONLY; + } + + return FULL_VALIDATION_REQUIRED; +} + +PRBool +xptiInterfaceInfoManager::AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + NS_ASSERTION(countOfFilesInFileList, "loser!"); + NS_ASSERTION(countOfFilesInFileList > aWorkingSet->GetFileCount(), "loser!"); + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // Make enough space in aWorkingset for additions to xptiFile array. + + if(!aWorkingSet->ExtendFileArray(countOfFilesInFileList)) + return PR_FALSE; + + // For each file that is not already in our working set, add any valid + // interfaces that don't conflict with previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + + if(xptiWorkingSet::NOT_FOUND != aWorkingSet->FindFile(dir, name.get())) + { + // This file was found in the working set, so skip it. + continue; + } + + LOG_AUTOREG((" finding interfaces in new file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR(""); + continue; + } + + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + else // its another kind of archive + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + 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) + { + // maybe there are no xpt files to register. + // a minimal install would have this case. + return PR_TRUE; + } + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // DEBUG_DumpFileArray(orderedFileArray, countOfFilesInFileList); + + // Make space in aWorkingset for a new xptiFile array. + + if(!aWorkingSet->NewFileArray(countOfFilesInFileList)) + return PR_FALSE; + + aWorkingSet->ClearZipItems(); + 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 = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + LOG_AUTOREG((" finding interfaces in file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + +// printf("* found %s\n", fileRecord.GetName()); + + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR("Unable to read an XPT file, turn logging on to see which file"); + LOG_AUTOREG((" unable to read file\n")); + continue; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + + else + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + return PR_TRUE; +} + +NS_IMPL_ISUPPORTS1(xptiZipLoaderSink, nsIXPTLoaderSink) + +// implement nsIXPTLoader +NS_IMETHODIMP +xptiZipLoaderSink::FoundEntry(const char* entryName, + PRInt32 index, + nsIInputStream *aStream) +{ + XPTHeader *header = + xptiZipLoader::ReadXPTFileFromInputStream(aStream, mWorkingSet); + if (!header) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mManager->FoundZipEntry(entryName, index, header, mWorkingSet)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// implement xptiEntrySink +PRBool +xptiInterfaceInfoManager::FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet) +{ + + NS_ASSERTION(entryName, "loser!"); + NS_ASSERTION(header, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + + int countOfInterfacesAddedForItem = 0; + xptiZipItem zipItemRecord(entryName, aWorkingSet); + + LOG_AUTOREG((" finding interfaces in file: %s\n", entryName)); + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d. Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + if(!header->num_interfaces) + { + // We are not interested in files without interfaces. + return PR_TRUE; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount(), + aWorkingSet->GetZipItemCount()); + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + 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, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + } + + // zipItemRecord.GetGuts()->SetEntryAt(k, entry); + ++countOfInterfacesAddedForItem; + } + + if(countOfInterfacesAddedForItem) + { + if(!aWorkingSet->GetZipItemFreeSpace()) + { + if(!aWorkingSet->ExtendZipItemArray( + aWorkingSet->GetZipItemCount() + 20)) + { + // out of space! + return PR_FALSE; + } + } + aWorkingSet->AppendZipItem(zipItemRecord); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded) +{ + NS_ASSERTION(iface, "loser!"); + NS_ASSERTION(entryAdded, "loser!"); + + *entryAdded = nsnull; + + if(!iface->interface_descriptor) + { + // Not resolved, ignore this one. + // XXX full logging might note this... + return PR_TRUE; + } + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, &iface->iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(entry) + { + // XXX validate this info to find possible inconsistencies + LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name)); + return PR_TRUE; + } + + // Build a new xptiInterfaceEntry object and hook it up. + + entry = xptiInterfaceEntry::NewEntry(iface->name, strlen(iface->name), + iface->iid, + typelibRecord, aWorkingSet); + if(!entry) + { + // XXX bad! + return PR_FALSE; + } + + //XXX We should SetHeader too as part of the validation, no? + entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags)); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + *entryAdded = entry; + + LOG_AUTOREG((" added interface: %s\n", iface->name)); + + return PR_TRUE; +} + +// local struct used to pass two pointers as one pointer +struct TwoWorkingSets +{ + TwoWorkingSets(xptiWorkingSet* src, xptiWorkingSet* dest) + : aSrcWorkingSet(src), aDestWorkingSet(dest) {} + + xptiWorkingSet* aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Merger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* srcEntry = ((xptiHashEntry*)hdr)->value; + xptiWorkingSet* aSrcWorkingSet = ((TwoWorkingSets*)arg)->aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet = ((TwoWorkingSets*)arg)->aDestWorkingSet; + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + srcEntry->GetTheIID(), PL_DHASH_LOOKUP); + + xptiInterfaceEntry* destEntry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(destEntry) + { + // Let's see if this is referring to the same exact typelib + + const char* destFilename = + aDestWorkingSet->GetTypelibFileName(destEntry->GetTypelibRecord()); + + const char* srcFilename = + aSrcWorkingSet->GetTypelibFileName(srcEntry->GetTypelibRecord()); + + if(0 == PL_strcmp(destFilename, srcFilename) && + (destEntry->GetTypelibRecord().GetZipItemIndex() == + srcEntry->GetTypelibRecord().GetZipItemIndex())) + { + // This is the same item. + // But... Let's make sure they didn't change the interface name. + // There are wacky developers that do stuff like that! + if(0 == PL_strcmp(destEntry->GetTheName(), srcEntry->GetTheName())) + return PL_DHASH_NEXT; + } + } + + // Clone the xptiInterfaceEntry into our destination WorkingSet. + + xptiTypelib typelibRecord; + + uint16 fileIndex = srcEntry->GetTypelibRecord().GetFileIndex(); + uint16 zipItemIndex = srcEntry->GetTypelibRecord().GetZipItemIndex(); + + fileIndex += aDestWorkingSet->mFileMergeOffsetMap[fileIndex]; + + // If it is not a zipItem, then the original index is fine. + if(srcEntry->GetTypelibRecord().IsZip()) + zipItemIndex += aDestWorkingSet->mZipItemMergeOffsetMap[zipItemIndex]; + + typelibRecord.Init(fileIndex, zipItemIndex); + + destEntry = xptiInterfaceEntry::NewEntry(*srcEntry, typelibRecord, + aDestWorkingSet); + if(!destEntry) + { + // XXX bad! should log + return PL_DHASH_NEXT; + } + + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mNameTable, + destEntry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + destEntry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + return PL_DHASH_NEXT; +} + +PRBool +xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet) +{ + + PRUint32 i; + + // Combine file lists. + + PRUint32 originalFileCount = aDestWorkingSet->GetFileCount(); + PRUint32 additionalFileCount = aSrcWorkingSet->GetFileCount(); + + // Create a new array big enough to hold both lists and copy existing files + + if(additionalFileCount) + { + if(!aDestWorkingSet->ExtendFileArray(originalFileCount + + additionalFileCount)) + 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->mFileMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalFileCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mFileMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalFileCount; ++i) + { + xptiFile& srcFile = aSrcWorkingSet->GetFileAt(i); + PRUint32 k; + for(k = 0; k < originalFileCount; ++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->mFileMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalFileCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetFileCount(); + + aDestWorkingSet->AppendFile(xptiFile(srcFile, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mFileMergeOffsetMap[i] = newIndex - i; + } + } + + // Combine ZipItem lists. + + PRUint32 originalZipItemCount = aDestWorkingSet->GetZipItemCount(); + PRUint32 additionalZipItemCount = aSrcWorkingSet->GetZipItemCount(); + + // Create a new array big enough to hold both lists and copy existing ZipItems + + if(additionalZipItemCount) + { + if(!aDestWorkingSet->ExtendZipItemArray(originalZipItemCount + + additionalZipItemCount)) + 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->mZipItemMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalZipItemCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mZipItemMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalZipItemCount; ++i) + { + xptiZipItem& srcZipItem = aSrcWorkingSet->GetZipItemAt(i); + PRUint32 k; + for(k = 0; k < originalZipItemCount; ++k) + { + // If ZipItem (with same name) is in both lists + // then reuse that record. + xptiZipItem& destZipItem = aDestWorkingSet->GetZipItemAt(k); + if(srcZipItem.Equals(destZipItem)) + { + aDestWorkingSet->mZipItemMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalZipItemCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetZipItemCount(); + + aDestWorkingSet->AppendZipItem( + xptiZipItem(srcZipItem, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mZipItemMergeOffsetMap[i] = newIndex - i; + } + } + + // Migrate xptiInterfaceInfos + + TwoWorkingSets sets(aSrcWorkingSet, aDestWorkingSet); + + PL_DHashTableEnumerate(aSrcWorkingSet->mNameTable, xpti_Merger, &sets); + + 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 file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + if(!file) + return PR_FALSE; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("* found %s\n", name.get()); + } + 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; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileArray(nsILocalFile** aFileArray, + PRUint32 count) +{ + // dump the sorted list + for(PRUint32 i = 0; i < count; ++i) + { + nsILocalFile* file = aFileArray[i]; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("found file: %s\n", name.get()); + } + return PR_TRUE; +} + +/***************************************************************************/ + +// static +void +xptiInterfaceInfoManager::WriteToLog(const char *fmt, ...) +{ + if(!gInterfaceInfoManager) + return; + + PRFileDesc* fd = gInterfaceInfoManager->GetOpenLogFile(); + if(fd) + { + va_list ap; + va_start(ap, fmt); + PR_vfprintf(fd, fmt, ap); + va_end(ap); + } +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ResolvedFileNameLogger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + xptiInterfaceInfoManager* mgr = (xptiInterfaceInfoManager*) arg; + + if(entry->IsFullyResolved()) + { + xptiWorkingSet* aWorkingSet = mgr->GetWorkingSet(); + PRFileDesc* fd = mgr->GetOpenLogFile(); + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + const char* filename = + aWorkingSet->GetFileAt(typelib.GetFileIndex()).GetName(); + + if(typelib.IsZip()) + { + const char* zipItemName = + aWorkingSet->GetZipItemAt(typelib.GetZipItemIndex()).GetName(); + PR_fprintf(fd, "xpti used interface: %s from %s::%s\n", + entry->GetTheName(), filename, zipItemName); + } + else + { + PR_fprintf(fd, "xpti used interface: %s from %s\n", + entry->GetTheName(), filename); + } + } + return PL_DHASH_NEXT; +} + +void +xptiInterfaceInfoManager::LogStats() +{ + PRUint32 i; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mStatsLogFile, PR_FALSE); + + PRFileDesc* fd = GetOpenLogFile(); + if(!fd) + return; + + // Show names of xpt (only) files from which at least one interface + // was resolved. + + PRUint32 fileCount = mWorkingSet.GetFileCount(); + for(i = 0; i < fileCount; ++i) + { + xptiFile& f = mWorkingSet.GetFileAt(i); + if(f.GetGuts()) + PR_fprintf(fd, "xpti used file: %s\n", f.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show names of xptfiles loaded from zips from which at least + // one interface was resolved. + + PRUint32 zipItemCount = mWorkingSet.GetZipItemCount(); + for(i = 0; i < zipItemCount; ++i) + { + xptiZipItem& zi = mWorkingSet.GetZipItemAt(i); + if(zi.GetGuts()) + PR_fprintf(fd, "xpti used file from zip: %s\n", zi.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show name of each interface that was fully resolved and the name + // of the file and (perhaps) zip from which it was loaded. + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, + xpti_ResolvedFileNameLogger, this); + +} + +/***************************************************************************/ + +// this is a private helper +static nsresult +EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) +{ + xptiInterfaceInfo* info; + nsresult rv; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + rv = entry->GetInterfaceInfo(&info); + if(NS_FAILED(rv)) + return rv; + + // Transfer the AddRef done by GetInterfaceInfo. + *_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info); + return NS_OK; +} + +/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIInterfaceInfo getInfoForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIIDPtr getIIDForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->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"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->GetName(_retval); +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + nsISupportsArray* array = (nsISupportsArray*) arg; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + array->AppendElement(ii); + return PL_DHASH_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; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayAppender, array); + + return array->Enumerate(_retval); +} + +struct ArrayAndPrefix +{ + nsISupportsArray* array; + const char* prefix; + PRUint32 length; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayPrefixAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + ArrayAndPrefix* args = (ArrayAndPrefix*) arg; + + const char* name = entry->GetTheName(); + if(name != PL_strnstr(name, args->prefix, args->length)) + return PL_DHASH_NEXT; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + args->array->AppendElement(ii); + return PL_DHASH_NEXT; +} + +/* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) +{ + nsCOMPtr array; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)}; + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayPrefixAppender, &args); + + return array->Enumerate(_retval); +} + +/* void autoRegisterInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces() +{ + nsCOMPtr fileList; + AutoRegMode mode; + PRBool ok; + + nsAutoLock lock(xptiInterfaceInfoManager::GetAutoRegLock(this)); + + xptiWorkingSet workingSet(mSearchPath); + if(!workingSet.IsValid()) + return NS_ERROR_UNEXPECTED; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mAutoRegLogFile, PR_TRUE); + + LOG_AUTOREG(("start AutoRegister\n")); + + // 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. + ok = xptiManifest::Read(this, &workingSet); + + LOG_AUTOREG(("read of manifest %s\n", ok ? "successful" : "FAILED")); + + // Grovel for all the typelibs we can find (in .xpt or .zip, .jar,...). + if(!BuildFileList(mSearchPath, getter_AddRefs(fileList)) || !fileList) + return NS_ERROR_UNEXPECTED; + + // DEBUG_DumpFileList(fileList); + + // Check to see how much work we need to do. + mode = DetermineAutoRegStrategy(mSearchPath, fileList, &workingSet); + + switch(mode) + { + case NO_FILES_CHANGED: + LOG_AUTOREG(("autoreg strategy: no files changed\n")); + LOG_AUTOREG(("successful end of AutoRegister\n")); + return NS_OK; + case FILES_ADDED_ONLY: + LOG_AUTOREG(("autoreg strategy: files added only\n")); + if(!AddOnlyNewFilesFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to add new files\n")); + return NS_ERROR_UNEXPECTED; + } + break; + case FULL_VALIDATION_REQUIRED: + LOG_AUTOREG(("autoreg strategy: doing full validation merge\n")); + if(!DoFullValidationMergeFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to do full validation\n")); + return NS_ERROR_UNEXPECTED; + } + break; + default: + NS_ERROR("switch missing a case"); + return NS_ERROR_UNEXPECTED; + } + + // Failure to write the manifest is not fatal in production builds. + // However, this would require the next startup to find and read all the + // xpt files. This will make that startup slower. If this ever becomes a + // chronic problem for anyone, then we'll want to figure out why! + + if(!xptiManifest::Write(this, &workingSet)) + { + LOG_AUTOREG(("FAILED to write manifest\n")); + NS_ERROR("Failed to write xpti manifest!"); + } + + if(!MergeWorkingSets(&mWorkingSet, &workingSet)) + { + LOG_AUTOREG(("FAILED to merge into live workingset\n")); + return NS_ERROR_UNEXPECTED; + } + +// DEBUG_DumpFileListInWorkingSet(mWorkingSet); + + LOG_AUTOREG(("successful end of AutoRegister\n")); + + return NS_OK; +} + +/***************************************************************************/ + +class xptiAdditionalManagersEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + xptiAdditionalManagersEnumerator(); + + PRBool SizeTo(PRUint32 likelyCount) {return mArray.SizeTo(likelyCount);} + PRBool AppendElement(nsIInterfaceInfoManager* element); + +private: + ~xptiAdditionalManagersEnumerator() {} + + nsSupportsArray mArray; + PRUint32 mIndex; + PRUint32 mCount; +}; + +NS_IMPL_ISUPPORTS1(xptiAdditionalManagersEnumerator, nsISimpleEnumerator) + +xptiAdditionalManagersEnumerator::xptiAdditionalManagersEnumerator() + : mIndex(0), mCount(0) +{ +} + +PRBool xptiAdditionalManagersEnumerator::AppendElement(nsIInterfaceInfoManager* element) +{ + if(!mArray.AppendElement(NS_STATIC_CAST(nsISupports*, element))) + return PR_FALSE; + mCount++; + return PR_TRUE; +} + +/* boolean hasMoreElements (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = mIndex < mCount; + return NS_OK; +} + +/* nsISupports getNext (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::GetNext(nsISupports **_retval) +{ + if(!(mIndex < mCount)) + { + NS_ERROR("Bad nsISimpleEnumerator caller!"); + return NS_ERROR_FAILURE; + } + + *_retval = mArray.ElementAt(mIndex++); + return *_retval ? NS_OK : NS_ERROR_FAILURE; +} + +/***************************************************************************/ + +/* void addAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AddAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToAdd = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + PRInt32 index; + nsresult rv = mAdditionalManagers.GetIndexOf(ptrToAdd, &index); + if(NS_FAILED(rv) || -1 != index) + return NS_ERROR_FAILURE; + if(!mAdditionalManagers.AppendElement(ptrToAdd)) + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +/* void removeAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::RemoveAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToRemove = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + if(!mAdditionalManagers.RemoveElement(ptrToRemove)) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +/* PRBool hasAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::HasAdditionalManagers(PRBool *_retval) +{ + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + *_retval = count != 0; + return rv; +} + +/* nsISimpleEnumerator enumerateAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateAdditionalManagers(nsISimpleEnumerator **_retval) +{ + nsAutoLock lock(mAdditionalManagersLock); + + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + if(NS_FAILED(rv)) + return rv; + + nsCOMPtr enumerator = + new xptiAdditionalManagersEnumerator(); + if(!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + enumerator->SizeTo(count); + + for(PRUint32 i = 0; i < count; /* i incremented in the loop body */) + { + nsCOMPtr raw = + dont_AddRef(mAdditionalManagers.ElementAt(i++)); + if(!raw) + return NS_ERROR_FAILURE; + nsCOMPtr weakRef = do_QueryInterface(raw); + if(weakRef) + { + nsCOMPtr manager = + do_QueryReferent(weakRef); + if(manager) + { + if(!enumerator->AppendElement(manager)) + return NS_ERROR_FAILURE; + } + else + { + // The manager is no more. Remove the element. + if(!mAdditionalManagers.RemoveElementAt(--i)) + return NS_ERROR_FAILURE; + count--; + } + } + else + { + // We *know* we put a pointer to either a nsIWeakReference or + // an nsIInterfaceInfoManager into the array, so we can avoid an + // extra QI here and just do a cast. + if(!enumerator->AppendElement( + NS_REINTERPRET_CAST(nsIInterfaceInfoManager*, raw.get()))) + return NS_ERROR_FAILURE; + } + } + + NS_ADDREF(*_retval = enumerator); + return NS_OK; +} + +/***************************************************************************/ + +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager() +{ + nsIInterfaceInfoManager* iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + NS_IF_ADDREF(iim); + return iim; +} + +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager() +{ + xptiInterfaceInfoManager::FreeInterfaceInfoManager(); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp new file mode 100644 index 00000000..03ab7029 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp @@ -0,0 +1,710 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiManifest. */ + +#include "xptiprivate.h" +#include "nsManifestLineReader.h" +#include "nsString.h" + +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 char g_TOKEN_AppDir[] = "AppDir"; +static const char g_TOKEN_Directories[] = "Directories"; + +static const int g_VERSION_MAJOR = 2; +static const int g_VERSION_MINOR = 0; + +/***************************************************************************/ + +static PRBool +GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, nsACString &aStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + if(appDir) + return NS_SUCCEEDED(appDir->GetPersistentDescriptor(aStr)); + return PR_FALSE; +} + +static PRBool +CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr, + const char *inStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inStr)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = appDir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_InterfaceWriter(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + PRFileDesc* fd = (PRFileDesc*) arg; + + char* iidStr = entry->GetTheIID()->ToString(); + if(!iidStr) + return PL_DHASH_STOP; + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + + PRBool success = PR_fprintf(fd, "%d,%s,%s,%d,%d,%d\n", + (int) number, + entry->GetTheName(), + iidStr, + (int) typelib.GetFileIndex(), + (int) (typelib.IsZip() ? + typelib.GetZipItemIndex() : -1), + (int) entry->GetScriptableFlag()); + + nsCRT::free(iidStr); + + return success ? PL_DHASH_NEXT : PL_DHASH_STOP; +} + + +// static +PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + + PRBool succeeded = PR_FALSE; + PRFileDesc* fd = nsnull; + PRUint32 i; + PRUint32 size32; + PRIntn interfaceCount = 0; + nsCAutoString appDirString; + + nsCOMPtr tempFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(tempFile)) || !tempFile) + return PR_FALSE; + + nsCAutoString originalLeafName; + tempFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + tempFile->SetNativeLeafName(leafName); + + // All exits via "goto out;" from here on... + if(NS_FAILED(tempFile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0600, &fd)) || !fd) + { + goto out; + } + + // write file header comments + + if(!PR_fprintf(fd, "%s\n", g_Disclaimer)) + goto out; + + // write the [Header] block, version number, and appdir. + + if(!PR_fprintf(fd, "\n[%s,%d]\n", g_TOKEN_Header, 2)) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%d,%d\n", + 0, g_TOKEN_Version, g_VERSION_MAJOR, g_VERSION_MINOR)) + goto out; + + GetCurrentAppDirString(aMgr, appDirString); + if(appDirString.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%s\n", + 1, g_TOKEN_AppDir, appDirString.get())) + goto out; + + // write Directories list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Directories, + (int) aWorkingSet->GetDirectoryCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetDirectoryCount(); i++) + { + nsCOMPtr dir; + nsCAutoString str; + + aWorkingSet->GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + goto out; + + dir->GetPersistentDescriptor(str); + if(str.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s\n", (int) i, str.get())) + goto out; + } + + // write Files list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Files, + (int) aWorkingSet->GetFileCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetFileCount(); i++) + { + const xptiFile& file = aWorkingSet->GetFileAt(i); + + LL_L2UI(size32, file.GetSize()); + + if(!PR_fprintf(fd, "%d,%s,%d,%u,%lld\n", + (int) i, + file.GetName(), + (int) file.GetDirectory(), + size32, PRInt64(file.GetDate()))) + goto out; + } + + // write ArchiveItems list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_ArchiveItems, + (int) aWorkingSet->GetZipItemCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetZipItemCount(); i++) + { + if(!PR_fprintf(fd, "%d,%s\n", + (int) i, + aWorkingSet->GetZipItemAt(i).GetName())) + goto out; + } + + // write the Interfaces list + + interfaceCount = aWorkingSet->mNameTable->entryCount; + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Interfaces, + (int) interfaceCount)) + goto out; + + if(interfaceCount != (PRIntn) + PL_DHashTableEnumerate(aWorkingSet->mNameTable, + xpti_InterfaceWriter, fd)) + goto out; + + + if(PR_SUCCESS == PR_Close(fd)) + { + succeeded = PR_TRUE; + } + fd = nsnull; + +out: + if(fd) + PR_Close(fd); + + if(succeeded) + { + // delete the old file and rename this + nsCOMPtr mainFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(mainFile)) || !mainFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(mainFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mainFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mainFile->GetParent(getter_AddRefs(parent)); + + // MoveTo means rename. + if(NS_FAILED(tempFile->MoveToNative(parent, originalLeafName))) + return PR_FALSE; + } + + return succeeded; +} + +/***************************************************************************/ +/***************************************************************************/ + +static char* +ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr, + PRUint32* pLength) +{ + PRFileDesc* fd = nsnull; + PRInt32 flen; + PRInt64 fileSize; + char* whole = nsnull; + PRBool success = PR_FALSE; + + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return nsnull; + +#ifdef DEBUG + { + static PRBool shown = PR_FALSE; + + nsCAutoString path; + if(!shown && NS_SUCCEEDED(aFile->GetNativePath(path)) && !path.IsEmpty()) + { + fprintf(stderr, "Type Manifest File: %s\n", path.get()); + shown = PR_TRUE; + } + } +#endif + + 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->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + goto out; + + if(flen > PR_Read(fd, whole, flen)) + goto out; + + success = PR_TRUE; + + out: + if(fd) + PR_Close(fd); + + if(!success) + { + delete [] whole; + return nsnull; + } + + *pLength = flen; + return whole; +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, + const char *token, int minCount, int* count) +{ + while(1) + { + if(!reader.NextLine()) + break; + if(*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if(*p != ']') + break; + *p = 0; + + char* values[2]; + int lengths[2]; + if(2 != reader.ParseLine(values, lengths, 2)) + break; + + // ignore the leading '[' + if(0 != PL_strcmp(values[0]+1, token)) + break; + + if((*count = atoi(values[1])) < minCount) + break; + + return PR_TRUE; + } + } + return PR_FALSE; +} + + +// static +PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + int i; + char* whole = nsnull; + PRBool succeeded = PR_FALSE; + PRUint32 flen = 0; + nsManifestLineReader reader; + xptiHashEntry* hashEntry; + int headerCount = 0; + int dirCount = 0; + int fileCount = 0; + int zipItemCount = -1; + int interfaceCount = 0; + int dir; + int flags; + char* values[6]; // 6 is currently the max items we need to parse + int lengths[6]; + PRUint32 size32; + PRInt64 size; + PRInt64 date; + + whole = ReadManifestIntoMemory(aMgr, &flen); + if(!whole) + return PR_FALSE; + + reader.Init(whole, flen); + + // All exits from here on should be via '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, 2, &headerCount)) + goto out; + + if(headerCount != 2) + goto out; + + // Verify the version number + + if(!reader.NextLine()) + goto out; + + // index,VersionLiteral,major,minor + if(4 != reader.ParseLine(values, lengths, 4)) + goto out; + + // index + if(0 != atoi(values[0])) + goto out; + + // VersionLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_Version)) + goto out; + + // major + if(g_VERSION_MAJOR != atoi(values[2])) + goto out; + + // minor + if(g_VERSION_MINOR != atoi(values[3])) + goto out; + + // Verify the application directory + + if(!reader.NextLine()) + goto out; + + // index,AppDirLiteral,directoryname + if(3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // index + if(1 != atoi(values[0])) + goto out; + + // AppDirLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_AppDir)) + goto out; + + if(!CurrentAppDirMatchesPersistentDescriptor(aMgr, values[2])) + goto out; + + // Look for "Directories" section + + if(!ReadSectionHeader(reader, g_TOKEN_Directories, 1, &dirCount)) + goto out; + else + { + // To validate that the directory list matches the current search path + // we first confirm that the list lengths match. + + nsCOMPtr searchPath; + aMgr->GetSearchPath(getter_AddRefs(searchPath)); + + PRUint32 searchPathCount; + searchPath->Count(&searchPathCount); + + if(dirCount != (int) searchPathCount) + goto out; + } + + // Read the directory records + + for(i = 0; i < dirCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,directoryname + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // directoryname + if(!aWorkingSet->DirectoryAtMatchesPersistentDescriptor(i, values[1])) + goto out; + } + + // Look for "Files" section + + if(!ReadSectionHeader(reader, g_TOKEN_Files, 1, &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; + + // index,filename,dirIndex,dilesSize,filesDate + if(5 != reader.ParseLine(values, lengths, 5)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // dirIndex + dir = atoi(values[2]); + if(dir < 0 || dir > dirCount) + goto out; + + // fileSize + size32 = atoi(values[3]); + if(size32 <= 0) + goto out; + LL_UI2L(size, size32); + + // fileDate + date = nsCRT::atoll(values[4]); + if(LL_IS_ZERO(date)) + goto out; + + // Append a new file record to the array. + + aWorkingSet->AppendFile( + xptiFile(nsInt64(size), nsInt64(date), dir, values[1], aWorkingSet)); + } + + // Look for "ZipItems" section + + if(!ReadSectionHeader(reader, g_TOKEN_ArchiveItems, 0, &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; + + // index,filename + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // Append a new zipItem record to the array. + + aWorkingSet->AppendZipItem(xptiZipItem(values[1], aWorkingSet)); + } + + // Look for "Interfaces" section + + if(!ReadSectionHeader(reader, g_TOKEN_Interfaces, 1, &interfaceCount)) + goto out; + + // Read the interface records + + for(i = 0; i < interfaceCount; ++i) + { + int fileIndex; + int zipItemIndex; + nsIID iid; + xptiInterfaceEntry* entry; + xptiTypelib typelibRecord; + + if(!reader.NextLine()) + goto out; + + // index,interfaceName,iid,fileIndex,zipIndex,flags + if(6 != reader.ParseLine(values, lengths, 6)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // interfaceName + if(!*values[1]) + goto out; + + // iid + if(!iid.Parse(values[2])) + goto out; + + // fileIndex + fileIndex = atoi(values[3]); + if(fileIndex < 0 || fileIndex >= fileCount) + goto out; + + // zipIndex (NOTE: -1 is a valid value) + zipItemIndex = atoi(values[4]); + if(zipItemIndex < -1 || zipItemIndex >= zipItemCount) + goto out; + + // flags + flags = atoi(values[5]); + if(flags != 0 && flags != 1) + goto out; + + // Build an InterfaceInfo and hook it in. + + if(zipItemIndex == -1) + typelibRecord.Init(fileIndex); + else + typelibRecord.Init(fileIndex, zipItemIndex); + + entry = xptiInterfaceEntry::NewEntry(values[1], lengths[1], + iid, typelibRecord, + aWorkingSet); + if(!entry) + goto out; + + entry->SetScriptableFlag(flags==1); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + } + + // success! + + succeeded = PR_TRUE; + + out: + if(whole) + delete [] whole; + + if(!succeeded) + { + // Cleanup the WorkingSet on failure. + aWorkingSet->InvalidateInterfaceInfos(); + aWorkingSet->ClearHashTables(); + aWorkingSet->ClearFiles(); + } + return succeeded; +} + +// static +PRBool xptiManifest::Delete(xptiInterfaceInfoManager* aMgr) +{ + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(aFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(aFile->Remove(PR_FALSE))) + return PR_FALSE; + + return PR_TRUE; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp new file mode 100644 index 00000000..a1dbf5c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of misc. xpti stuff. */ + +#include "xptiprivate.h" + +struct xptiFileTypeEntry +{ + const char* name; + int len; + xptiFileType::Type type; +}; + +static const xptiFileTypeEntry g_Entries[] = + { + {".xpt", 4, xptiFileType::XPT}, + {".zip", 4, xptiFileType::ZIP}, + {".jar", 4, xptiFileType::ZIP}, + {nsnull, 0, xptiFileType::UNKNOWN} + }; + +// static +xptiFileType::Type xptiFileType::GetType(const char* name) +{ + NS_ASSERTION(name, "loser!"); + int len = PL_strlen(name); + for(const xptiFileTypeEntry* p = g_Entries; p->name; p++) + { + if(len > p->len && 0 == PL_strcasecmp(p->name, &(name[len - p->len]))) + return p->type; + } + return UNKNOWN; +} + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiAutoLog) + +xptiAutoLog::xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append) + : mMgr(nsnull), mOldFileDesc(nsnull) +{ + MOZ_COUNT_CTOR(xptiAutoLog); + + if(mgr && logfile) + { + PRFileDesc* fd; + if(NS_SUCCEEDED(logfile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_APPEND | + (append ? 0 : PR_TRUNCATE), + 0600, &fd)) && fd) + { +#ifdef DEBUG + m_DEBUG_FileDesc = fd; +#endif + mMgr = mgr; + mOldFileDesc = mMgr->SetOpenLogFile(fd); + if(append) + PR_Seek(fd, 0, PR_SEEK_END); + WriteTimestamp(fd, "++++ start logging "); + + } + else + { +#ifdef DEBUG + printf("xpti failed to open log file for writing\n"); +#endif + } + } +} + +xptiAutoLog::~xptiAutoLog() +{ + MOZ_COUNT_DTOR(xptiAutoLog); + + if(mMgr) + { + PRFileDesc* fd = mMgr->SetOpenLogFile(mOldFileDesc); + NS_ASSERTION(fd == m_DEBUG_FileDesc, "bad unravel"); + if(fd) + { + WriteTimestamp(fd, "---- end logging "); + PR_Close(fd); + } + } +} + +void xptiAutoLog::WriteTimestamp(PRFileDesc* fd, const char* msg) +{ + PRExplodedTime expTime; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &expTime); + char time[128]; + PR_FormatTimeUSEnglish(time, 128, "%Y-%m-%d-%H:%M:%S", &expTime); + PR_fprintf(fd, "\n%s %s\n\n", msg, time); +} + +/***************************************************************************/ + +nsresult +xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile) +{ + nsresult rv; + nsCOMPtr cloneRaw; + + rv = aLocalFile->Clone(getter_AddRefs(cloneRaw)); + if(NS_FAILED(rv)) + return rv; + + return CallQueryInterface(cloneRaw, aCloneLocalFile); +} + + +nsresult +xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile) +{ + nsresult rv; + nsCOMPtr original; + + rv = aArray->QueryElementAt(aIndex, NS_GET_IID(nsILocalFile), + getter_AddRefs(original)); + if(NS_FAILED(rv)) + return rv; + + return xptiCloneLocalFile(original, aLocalFile); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp new file mode 100644 index 00000000..50956585 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiTypelibGuts. */ + +#include "xptiprivate.h" + +// static +xptiTypelibGuts* +xptiTypelibGuts::NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aHeader, "bad param"); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiTypelibGuts) + + (sizeof(xptiInterfaceEntry*) * + (aHeader->num_interfaces - 1))); + if(!place) + return nsnull; + return new(place) xptiTypelibGuts(aHeader); +} + +xptiTypelibGuts::xptiTypelibGuts(XPTHeader* aHeader) + : mHeader(aHeader) +{ + // empty +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp new file mode 100644 index 00000000..b9602726 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiWorkingSet. */ + +#include "xptiprivate.h" +#include "nsString.h" + +#define XPTI_STRING_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_HASHTABLE_SIZE 128 + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +IIDGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheIID(); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +IIDHash(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber) ((const nsIID*)key)->m0; +} + +PR_STATIC_CALLBACK(PRBool) +IIDMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const nsIID* iid1 = ((xptiHashEntry*)entry)->value->GetTheIID(); + const nsIID* iid2 = (const nsIID*)key; + + return iid1 == iid2 || iid1->Equals(*iid2); +} + +const static struct PLDHashTableOps IIDTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + IIDGetKey, + IIDHash, + IIDMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +NameGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheName(); +} + +PR_STATIC_CALLBACK(PRBool) +NameMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const char* str1 = ((xptiHashEntry*)entry)->value->GetTheName(); + const char* str2 = (const char*) key; + return str1 == str2 || 0 == PL_strcmp(str1, str2); +} + +static const struct PLDHashTableOps NameTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + NameGetKey, + PL_DHashStringKey, + NameMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiWorkingSet) + +xptiWorkingSet::xptiWorkingSet(nsISupportsArray* aDirectories) + : 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")), + mDirectories(aDirectories), + mNameTable(PL_NewDHashTable(&NameTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mIIDTable(PL_NewDHashTable(&IIDTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mFileMergeOffsetMap(nsnull), + mZipItemMergeOffsetMap(nsnull) +{ + MOZ_COUNT_CTOR(xptiWorkingSet); + // do nothing else... +} + +PRBool +xptiWorkingSet::IsValid() const +{ + return (mFileCount == 0 || mFileArray) && + (mZipItemCount == 0 || mZipItemArray) && + mStringArena && + mStructArena && + mNameTable && + mIIDTable; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Remover(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + return PL_DHASH_REMOVE; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Invalidator(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + entry->LockedInvalidateInterfaceInfo(); + return PL_DHASH_NEXT; +} + +void +xptiWorkingSet::InvalidateInterfaceInfos() +{ + if(mNameTable) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + PL_DHashTableEnumerate(mNameTable, xpti_Invalidator, nsnull); + } +} + +void +xptiWorkingSet::ClearHashTables() +{ + if(mNameTable) + PL_DHashTableEnumerate(mNameTable, xpti_Remover, nsnull); + + if(mIIDTable) + PL_DHashTableEnumerate(mIIDTable, xpti_Remover, 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() +{ + MOZ_COUNT_DTOR(xptiWorkingSet); + + ClearFiles(); + ClearZipItems(); + ClearHashTables(); + + if(mNameTable) + PL_DHashTableDestroy(mNameTable); + + if(mIIDTable) + PL_DHashTableDestroy(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); + } +} + +PRUint32 +xptiWorkingSet::FindFile(PRUint32 dir, const char* name) +{ + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount;++i) + { + xptiFile& file = mFileArray[i]; + if(file.GetDirectory() == dir && + 0 == PL_strcmp(name, file.GetName())) + { + return i; + } + } + } + return NOT_FOUND; +} + +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; +} + +/***************************************************************************/ + +PRUint32 +xptiWorkingSet::FindZipItemWithName(const char* name) +{ + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount;++i) + if(0 == PL_strcmp(name, mZipItemArray[i].GetName())) + return i; + } + return NOT_FOUND; +} + +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; +} + +/***************************************************************************/ +// Directory stuff... + +PRUint32 xptiWorkingSet::GetDirectoryCount() +{ + PRUint32 count = 0; + mDirectories->Count(&count); + return count; +} + +nsresult xptiWorkingSet::GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return xptiCloneElementAsLocalFile(mDirectories, i, dir); +} + +nsresult xptiWorkingSet::GetDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), (void**)dir); +} + +PRBool xptiWorkingSet::FindDirectory(nsILocalFile* dir, PRUint32* index) +{ + PRUint32 count; + nsresult rv = mDirectories->Count(&count); + if(NS_FAILED(rv)) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + PRBool same; + nsCOMPtr current; + mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), + getter_AddRefs(current)); + if(!current || NS_FAILED(current->Equals(dir, &same))) + break; + if(same) + { + *index = i; + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool xptiWorkingSet::FindDirectoryOfFile(nsILocalFile* file, PRUint32* index) +{ + nsCOMPtr dirAbstract; + file->GetParent(getter_AddRefs(dirAbstract)); + if(!dirAbstract) + return PR_FALSE; + nsCOMPtr dir = do_QueryInterface(dirAbstract); + if(!dir) + return PR_FALSE; + return FindDirectory(dir, index); +} + +PRBool xptiWorkingSet::DirectoryAtMatchesPersistentDescriptor(PRUint32 i, + const char* inDesc) +{ + nsCOMPtr dir; + GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + return PR_FALSE; + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inDesc)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = dir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp new file mode 100644 index 00000000..c9a6178b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiZipItem. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiZipItem) + +xptiZipItem::xptiZipItem() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + // empty +} + +xptiZipItem::xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet) + + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(aName), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); +} + +xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); +} + +xptiZipItem::~xptiZipItem() +{ + MOZ_COUNT_DTOR(xptiZipItem); +} + +PRBool +xptiZipItem::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp new file mode 100644 index 00000000..caba49d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Implementation of xptiZipLoader. */ + +#include "xptiprivate.h" + +XPTHeader* +xptiZipLoader::ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet) +{ + XPTCursor cursor; + PRUint32 totalRead = 0; + XPTState *state = nsnull; + XPTHeader *header = nsnull; + + PRUint32 flen; + stream->Available(&flen); + + char *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)) + { + header = nsnull; + goto out; + } + + out: + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + return header; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h new file mode 100644 index 00000000..3d159c2c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h @@ -0,0 +1,981 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* 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 "nsIXPTLoader.h" + +#include "nsIServiceManager.h" +#include "nsILocalFile.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIWeakReference.h" + +#include "nsCRT.h" +#include "nsMemory.h" + +#include "nsISupportsArray.h" +#include "nsSupportsArray.h" +#include "nsInt64.h" + +#include "nsQuickSort.h" + +#include "nsXPIDLString.h" + +#include "nsIInputStream.h" + +#include "nsAutoLock.h" + +#include "pldhash.h" +#include "plstr.h" +#include "prprf.h" +#include "prio.h" +#include "prtime.h" +#include "prenv.h" + +#include +#include + +/***************************************************************************/ + +#if 0 && defined(DEBUG_jband) +#define LOG_RESOLVE(x) printf x +#define LOG_LOAD(x) printf x +#define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0) +#else +#define LOG_RESOLVE(x) ((void)0) +#define LOG_LOAD(x) ((void)0) +#define LOG_AUTOREG(x) xptiInterfaceInfoManager::WriteToLog x +#endif + +#if 1 && defined(DEBUG_jband) +#define SHOW_INFO_COUNT_STATS +#endif + +/***************************************************************************/ + +class xptiFile; +class xptiInterfaceInfo; +class xptiInterfaceInfoManager; +class xptiInterfaceEntry; +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; +}; + +/***************************************************************************/ + +// No virtuals. +// These are always constructed in the struct arena using placement new. +// dtor need not be called. + +class xptiTypelibGuts +{ +public: + static xptiTypelibGuts* NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet); + + XPTHeader* GetHeader() {return mHeader;} + PRUint16 GetEntryCount() const {return mHeader->num_interfaces;} + + void SetEntryAt(PRUint16 i, xptiInterfaceEntry* ptr) + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + mEntryArray[i] = ptr; + } + + xptiInterfaceEntry* GetEntryAt(PRUint16 i) const + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + return mEntryArray[i]; + } + +private: + xptiTypelibGuts(); // not implemented + xptiTypelibGuts(XPTHeader* aHeader); + ~xptiTypelibGuts() {} + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + +private: + XPTHeader* mHeader; // hold pointer into arena + xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit. +}; + +/***************************************************************************/ + +class xptiFile +{ +public: + const nsInt64& GetSize() const {return mSize;} + const nsInt64& GetDate() const {return mDate;} + const char* GetName() const {return mName;} + /*const*/ PRUint32 GetDirectory() const {return mDirectory;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiFile(); + + xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet); + + ~xptiFile(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + PRBool Equals(const xptiFile& r) const + { + return mDirectory == r.mDirectory && + 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) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mSize = r.mSize; + mDate = r.mDate; + mName = r.mName; + mDirectory = r.mDirectory; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + nsInt64 mSize; + nsInt64 mDate; + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena + PRUint32 mDirectory; +}; + +/***************************************************************************/ + +class xptiZipItem +{ +public: + const char* GetName() const {return mName;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiZipItem(); + + xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet); + + ~xptiZipItem(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + 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) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mName = r.mName; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena +}; + +/***************************************************************************/ + +class xptiWorkingSet +{ +public: + xptiWorkingSet(); // not implmented + xptiWorkingSet(nsISupportsArray* aDirectories); + ~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(); + } + + enum {NOT_FOUND = 0xffffffff}; + + // FileArray stuff... + + PRUint32 GetFileCount() const {return mFileCount;} + PRUint32 GetFileFreeSpace() + {return mFileArray ? mMaxFileCount - mFileCount : 0;} + + PRUint32 FindFile(PRUint32 dir, const char* name); + + PRUint32 GetTypelibDirectoryIndex(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetDirectory(); + } + + const char* GetTypelibFileName(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetName(); + } + + 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;} + + PRUint32 FindZipItemWithName(const char* name); + + 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); + + // Directory stuff... + + PRUint32 GetDirectoryCount(); + nsresult GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir); + nsresult GetDirectoryAt(PRUint32 i, nsILocalFile** dir); + PRBool FindDirectory(nsILocalFile* dir, PRUint32* index); + PRBool FindDirectoryOfFile(nsILocalFile* file, PRUint32* index); + PRBool DirectoryAtMatchesPersistentDescriptor(PRUint32 i, const char* desc); + + // 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; + + nsCOMPtr mDirectories; + +public: + // XXX make these private with accessors + PLDHashTable* mNameTable; + PLDHashTable* mIIDTable; + PRUint32* mFileMergeOffsetMap; // always in an arena + PRUint32* mZipItemMergeOffsetMap; // always in an arena +}; + +/***************************************************************************/ + +class xptiInterfaceGuts +{ +public: + uint16 mMethodBaseIndex; + uint16 mConstantBaseIndex; + xptiInterfaceEntry* mParent; + XPTInterfaceDescriptor* mDescriptor; + xptiTypelib mTypelib; + xptiWorkingSet* mWorkingSet; + + static xptiInterfaceGuts* NewGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + { + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceGuts)); + if(!place) + return nsnull; + return new(place) xptiInterfaceGuts(aDescriptor, aTypelib, aWorkingSet); + } + +private: + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + xptiInterfaceGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + : mMethodBaseIndex(0), + mConstantBaseIndex(0), + mParent(nsnull), + mDescriptor(aDescriptor), + mTypelib(aTypelib), + mWorkingSet(aWorkingSet) {} + + ~xptiInterfaceGuts() {} +}; + +/***************************************************************************/ + +// This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value +// and a set of bitflags in one 8bit value. See below. + +class xptiInfoFlags +{ + enum {STATE_MASK = 3}; +public: + xptiInfoFlags(uint8 n) : mData(n) {} + xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {} + + static uint8 GetStateMask() + {return uint8(STATE_MASK);} + + void Clear() + {mData = 0;} + + uint8 GetData() const + {return mData;} + + uint8 GetState() const + {return mData & GetStateMask();} + + void SetState(uint8 state) + {mData &= ~GetStateMask(); mData |= state;} + + void SetFlagBit(uint8 flag, PRBool on) + {if(on) + mData |= ~GetStateMask() & flag; + else + mData &= GetStateMask() | ~flag;} + + PRBool GetFlagBit(uint8 flag) const + {return (mData & flag) ? PR_TRUE : PR_FALSE;} + +private: + uint8 mData; +}; + +/****************************************************/ + +// No virtual methods. +// We always create in the struct arena and construct using "placement new". +// No members need dtor calls. + +class xptiInterfaceEntry +{ +public: + static xptiInterfaceEntry* NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + static xptiInterfaceEntry* NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + enum { + NOT_RESOLVED = 0, + PARTIALLY_RESOLVED = 1, + FULLY_RESOLVED = 2, + RESOLVE_FAILED = 3 + }; + + // Additional bit flags... + enum {SCRIPTABLE = 4}; + + uint8 GetResolveState() const {return mFlags.GetState();} + + PRBool IsFullyResolved() const + {return GetResolveState() == (uint8) 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;} + + xptiInterfaceGuts* GetInterfaceGuts() const + {return HasInterfaceRecord() ? mInterface : nsnull;} + +#ifdef DEBUG + PRBool DEBUG_ScriptableFlagIsValid() const + {int s = (int) GetResolveState(); + if((s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface) + { + if(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)) + return GetScriptableFlag(); + return !GetScriptableFlag(); + } + return PR_TRUE; + } +#endif + + void SetScriptableFlag(PRBool on) + {mFlags.SetFlagBit(uint8(SCRIPTABLE),on);} + PRBool GetScriptableFlag() const + {return mFlags.GetFlagBit(uint8(SCRIPTABLE));} + + const nsID* GetTheIID() const {return &mIID;} + const char* GetTheName() const {return mName;} + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);} + + PRBool PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet); + + nsresult GetInterfaceInfo(xptiInterfaceInfo** info); + PRBool InterfaceInfoEquals(const xptiInterfaceInfo* info) const + {return info == mInfo;} + + void LockedInvalidateInterfaceInfo(); + void LockedInterfaceInfoDeathNotification() {mInfo = nsnull;} + + ////////////////////// + // These non-virtual methods handle the delegated nsIInterfaceInfo methods. + + nsresult GetName(char * *aName); + nsresult GetIID(nsIID * *aIID); + nsresult IsScriptable(PRBool *_retval); + // Except this one. + //nsresult GetParent(nsIInterfaceInfo * *aParent); + nsresult GetMethodCount(PRUint16 *aMethodCount); + nsresult GetConstantCount(PRUint16 *aConstantCount); + nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info); + nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info); + nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant); + nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval); + nsresult GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval); + nsresult GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval); + nsresult GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval); + nsresult IsIID(const nsIID * IID, PRBool *_retval); + nsresult GetNameShared(const char **name); + nsresult GetIIDShared(const nsIID * *iid); + nsresult IsFunction(PRBool *_retval); + nsresult HasAncestor(const nsIID * iid, PRBool *_retval); + nsresult GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid); + + ////////////////////// + +private: + xptiInterfaceEntry(); // not implemented + + xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib); + + xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib); + ~xptiInterfaceEntry(); + + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + + void SetResolvedState(int state) + {mFlags.SetState(uint8(state));} + + PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull); + + // We only call these "*Locked" variants after locking. This is done to + // allow reentrace as files are loaded and various interfaces resolved + // without having to worry about the locked state. + + PRBool EnsureResolvedLocked(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : ResolveLocked(aWorkingSet);} + PRBool ResolveLocked(xptiWorkingSet* aWorkingSet = nsnull); + + // private helpers + + nsresult GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry); + + nsresult GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type); + +private: + nsID mIID; + union { + xptiTypelib mTypelib; // Valid only until resolved. + xptiInterfaceGuts* mInterface; // Valid only after resolved. + }; + xptiInterfaceInfo* mInfo; // May come and go. + xptiInfoFlags mFlags; + char mName[1]; // Always last. Sized to fit. +}; + +struct xptiHashEntry : public PLDHashEntryHdr +{ + xptiInterfaceEntry* value; +}; + +/****************************************************/ + +class xptiInterfaceInfo : public nsIInterfaceInfo +{ +public: + NS_DECL_ISUPPORTS + + // Use delegation to implement (most!) of nsIInterfaceInfo. + NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); } + NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); } + NS_IMETHOD IsScriptable(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); } + // Except this one. + NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) + { + if(!EnsureResolved() || !EnsureParent()) + return NS_ERROR_UNEXPECTED; + NS_IF_ADDREF(*aParent = mParent); + return NS_OK; + } + NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); } + NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); } + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); } + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); } + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); } + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); } + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); } + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetLengthIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); } + NS_IMETHOD IsIID(const nsIID * IID, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); } + NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); } + NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); } + NS_IMETHOD IsFunction(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); } + NS_IMETHOD HasAncestor(const nsIID * iid, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); } + NS_IMETHOD GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); } + +public: + xptiInterfaceInfo(xptiInterfaceEntry* entry); + + void Invalidate() + {NS_IF_RELEASE(mParent); mEntry = nsnull;} + +#ifdef DEBUG + static void DEBUG_ShutdownNotification(); +#endif + +private: + + ~xptiInterfaceInfo(); + + // Note that mParent might still end up as nsnull if we don't have one. + PRBool EnsureParent(xptiWorkingSet* aWorkingSet = nsnull) + { + NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call"); + return mParent || !mEntry->GetInterfaceGuts()->mParent || BuildParent(); + } + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + { + return mEntry && mEntry->EnsureResolved(aWorkingSet); + } + + PRBool BuildParent() + { + NS_ASSERTION(mEntry && + mEntry->IsFullyResolved() && + !mParent && + mEntry->GetInterfaceGuts()->mParent, + "bad BuildParent call"); + return NS_SUCCEEDED(mEntry->GetInterfaceGuts()->mParent-> + GetInterfaceInfo(&mParent)); + } + + xptiInterfaceInfo(); // not implemented + +private: + xptiInterfaceEntry* mEntry; + xptiInterfaceInfo* mParent; +}; + +/***************************************************************************/ + +class xptiManifest +{ +public: + static PRBool Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Delete(xptiInterfaceInfoManager* aMgr); + +private: + xptiManifest(); // no implementation +}; + +/***************************************************************************/ + +class xptiZipLoaderSink : public nsIXPTLoaderSink +{ +public: + xptiZipLoaderSink(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) : + mManager(aMgr), + mWorkingSet(aWorkingSet) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIXPTLOADERSINK + +private: + ~xptiZipLoaderSink() {} + + xptiInterfaceInfoManager* mManager; + xptiWorkingSet* mWorkingSet; + +}; + +class xptiZipLoader +{ +public: + xptiZipLoader(); // not implemented + + static XPTHeader* + ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet); + +}; + + +/***************************************************************************/ + +class xptiFileType +{ +public: + enum Type {UNKNOWN = -1, XPT = 0, ZIP = 1 }; + + static Type GetType(const char* name); + + static PRBool IsUnknown(const char* name) + {return GetType(name) == UNKNOWN;} + + static PRBool IsXPT(const char* name) + {return GetType(name) == XPT;} + + static PRBool IsZip(const char* name) + {return GetType(name) == ZIP;} +private: + xptiFileType(); // no implementation +}; + +/***************************************************************************/ + +// We use this is as a fancy way to open a logfile to be used within the scope +// of some given function where it is instantiated. + +class xptiAutoLog +{ +public: + xptiAutoLog(); // not implemented + xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append); + ~xptiAutoLog(); +private: + void WriteTimestamp(PRFileDesc* fd, const char* msg); + + xptiInterfaceInfoManager* mMgr; + PRFileDesc* mOldFileDesc; +#ifdef DEBUG + PRFileDesc* m_DEBUG_FileDesc; +#endif +}; + +/***************************************************************************/ + +class xptiInterfaceInfoManager + : public nsIInterfaceInfoSuperManager +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFOMANAGER + NS_DECL_NSIINTERFACEINFOSUPERMANAGER + + // helper + PRBool + FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet); + +public: + static xptiInterfaceInfoManager* GetInterfaceInfoManagerNoAddRef(); + static void FreeInterfaceInfoManager(); + + xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;} + PRFileDesc* GetOpenLogFile() {return mOpenLogFile;} + PRFileDesc* SetOpenLogFile(PRFileDesc* fd) + {PRFileDesc* temp = mOpenLogFile; mOpenLogFile = fd; return temp;} + + PRBool LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet = nsnull); + + PRBool GetApplicationDir(nsILocalFile** aDir); + PRBool GetCloneOfManifestLocation(nsILocalFile** aDir); + + void GetSearchPath(nsISupportsArray** aSearchPath) + {NS_ADDREF(*aSearchPath = mSearchPath);} + + static PRLock* GetResolveLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mResolveLock;} + + static PRLock* GetAutoRegLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mAutoRegLock;} + + static PRMonitor* GetInfoMonitor(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mInfoMonitor;} + + static void WriteToLog(const char *fmt, ...); + +private: + ~xptiInterfaceInfoManager(); + xptiInterfaceInfoManager(); // not implmented + xptiInterfaceInfoManager(nsISupportsArray* aSearchPath); + + enum AutoRegMode { + NO_FILES_CHANGED = 0, + FILES_ADDED_ONLY, + FULL_VALIDATION_REQUIRED + }; + + PRBool IsValid(); + + PRBool BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList); + + nsILocalFile** BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + XPTHeader* ReadXPTFile(nsILocalFile* aFile, xptiWorkingSet* aWorkingSet); + + AutoRegMode DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded); + + PRBool MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet); + + void LogStats(); + + PRBool DEBUG_DumpFileList(nsISupportsArray* aFileList); + PRBool DEBUG_DumpFileArray(nsILocalFile** aFileArray, PRUint32 count); + PRBool DEBUG_DumpFileListInWorkingSet(xptiWorkingSet* aWorkingSet); + + static PRBool BuildFileSearchPath(nsISupportsArray** aPath); + +private: + xptiWorkingSet mWorkingSet; + nsCOMPtr mStatsLogFile; + nsCOMPtr mAutoRegLogFile; + PRFileDesc* mOpenLogFile; + PRLock* mResolveLock; + PRLock* mAutoRegLock; + PRMonitor* mInfoMonitor; + PRLock* mAdditionalManagersLock; + nsSupportsArray mAdditionalManagers; + nsCOMPtr mSearchPath; +}; + +/***************************************************************************/ +// utilities... + +nsresult xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile); + +nsresult xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile); + +#endif /* xptiprivate_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore new file mode 100644 index 00000000..f29041e6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestInterfaceInfo diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in new file mode 100644 index 00000000..9b7f1ed4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla 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/MPL/ +# +# 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 the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +SIMPLE_PROGRAMS = TestInterfaceInfo$(BIN_SUFFIX) + +CPPSRCS = TestInterfaceInfo.cpp + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp new file mode 100644 index 00000000..75005c50 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* Some simple smoke tests of the typelib loader. */ + +#include "nscore.h" + +#include "nsISupports.h" +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" + +#include + +// This file expects the nsInterfaceInfoManager to be able to discover +// .xpt files corresponding to those in xpcom/idl. Currently this +// means setting XPTDIR in the environment to some directory +// containing these files. + +int main (int argc, char **argv) { + int i; + nsIID *iid1, *iid2, *iid3; + char *name1, *name2, *name3; + nsIInterfaceInfo *info2, *info3, *info4, *info5; + + nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager(); + + fprintf(stderr, "\ngetting iid for 'nsISupports'\n"); + iim->GetIIDForName("nsISupports", &iid1); + iim->GetNameForIID(iid1, &name1); + fprintf(stderr, "%s iid %s\n", name1, iid1->ToString()); + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid2); + iim->GetNameForIID(iid2, &name2); + fprintf(stderr, "%s iid %s\n", name2, iid2->ToString()); + + fprintf(stderr, "iid: %s, name: %s\n", iid1->ToString(), name1); + fprintf(stderr, "iid: %s, name: %s\n", iid2->ToString(), name2); + + fprintf(stderr, "\ngetting info for iid2 from above\n"); + iim->GetInfoForIID(iid2, &info2); +#ifdef DEBUG +// ((nsInterfaceInfo *)info2)->print(stderr); +#endif + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid3); + iim->GetNameForIID(iid3, &name3); + fprintf(stderr, "%s iid %s\n", name3, iid2->ToString()); + iim->GetInfoForIID(iid3, &info3); +#ifdef DEBUG +// ((nsInterfaceInfo *)info3)->print(stderr); +#endif + + fprintf(stderr, "\ngetting info for name 'nsIBidirectionalEnumerator'\n"); + iim->GetInfoForName("nsIBidirectionalEnumerator", &info4); +#ifdef DEBUG +// ((nsInterfaceInfo *)info4)->print(stderr); +#endif + + fprintf(stderr, "\nparams work?\n"); + fprintf(stderr, "\ngetting info for name 'nsIServiceManager'\n"); + iim->GetInfoForName("nsIServiceManager", &info5); +#ifdef DEBUG +// ((nsInterfaceInfo *)info5)->print(stderr); +#endif + + // XXX: nsIServiceManager is no more; what do we test with? + if (info5 == NULL) { + fprintf(stderr, "\nNo nsIServiceManager; cannot continue.\n"); + return 1; + } + + uint16 methodcount; + info5->GetMethodCount(&methodcount); + const nsXPTMethodInfo *mi; + for (i = 0; i < methodcount; i++) { + info5->GetMethodInfo(i, &mi); + fprintf(stderr, "method %d, name %s\n", i, mi->GetName()); + } + + // 7 is GetServiceWithListener, which has juicy params. + info5->GetMethodInfo(7, &mi); +// uint8 paramcount = mi->GetParamCount(); + + nsXPTParamInfo param2 = mi->GetParam(2); + // should be IID for nsIShutdownListener + nsIID *nsISL; + info5->GetIIDForParam(7, ¶m2, &nsISL); +// const nsIID *nsISL = param2.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 2 of method 7 of GetServiceWithListener - %s\n", nsISL->ToString()); + // if we look up the name? + char *nsISLname; + iim->GetNameForIID(nsISL, &nsISLname); + fprintf(stderr, "which is called %s\n", nsISLname); + + fprintf(stderr, "\nhow about one defined in a different typelib\n"); + nsXPTParamInfo param3 = mi->GetParam(3); + // should be IID for nsIShutdownListener + nsIID *nsISS; + info5->GetIIDForParam(7, ¶m3, &nsISS); +// const nsIID *nsISS = param3.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 3 of method 7 of GetServiceWithListener - %s\n", nsISS->ToString()); + // if we look up the name? + char *nsISSname; + iim->GetNameForIID(nsISS, &nsISSname); + fprintf(stderr, "which is called %s\n", nsISSname); + + return 0; +} + -- cgit v1.2.3