diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /src/libs/xpcom18a4/java | |
parent | Initial commit. (diff) | |
download | virtualbox-16f504a9dca3fe3b70568f67b7d41241ae485288.tar.xz virtualbox-16f504a9dca3fe3b70568f67b7d41241ae485288.zip |
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs/xpcom18a4/java')
44 files changed, 13573 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/java/Makefile.kmk b/src/libs/xpcom18a4/java/Makefile.kmk new file mode 100644 index 00000000..56c34c95 --- /dev/null +++ b/src/libs/xpcom18a4/java/Makefile.kmk @@ -0,0 +1,233 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Java bindings +# + +# +# Copyright (C) 2010-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# +# Globals +# +VBOX_JXPCOM_SRC := $(PATH_SUB_CURRENT) + +VBOX_JXPCOM_TARGET := $(PATH_TARGET)/vboxjxpcom-gen +VBOX_JXPCOM_JDEST := $(VBOX_JXPCOM_TARGET)/jdest + +VBOX_GLUE_XSLT_DIR := $(PATH_ROOT)/src/VBox/Main/glue + +ifndef VBOX_ONLY_SDK +# +# VBoxJXpcom - Java<->XPCOM native library +# +DLLS += VBoxJXpcom + +VBoxJXpcom_TEMPLATE = XPCOM +VBoxJXpcom_CXXFLAGS = -Wno-write-strings +VBoxJXpcom_DEFS = \ + EXPORT_XPTI_API \ + EXPORT_XPT_API \ + VBOX_WITH_XPCOM +VBoxJXpcom_NAME = libvboxjxpcom +VBoxJXpcom_DLLSUFF.darwin = .jnilib +VBoxJXpcom_INCS = \ + src \ + $(VBOX_JAVA_INC) \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/glue \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/build \ + $(VBOX_JXPCOM_JDEST) +VBoxJXpcom_SOURCES = \ + src/nsAppFileLocProviderProxy.cpp \ + src/nsJavaWrapper.cpp \ + src/nsJavaXPCOMBindingUtils.cpp \ + src/nsJavaXPTCStub.cpp \ + src/nsJavaXPTCStubWeakRef.cpp \ + src/nsJavaXPCOMGlue.cpp \ + src/nsJavaInterfaces.cpp +VBoxJXpcom_LIBS = \ + $(PATH_STAGE_LIB)/VBoxCOM$(VBOX_SUFF_LIB) \ + $(PATH_STAGE_BIN)/VBoxXPCOM$(VBOX_SUFF_DLL) + +#VBoxJXpcom_ORDERDEPS = $(VBOX_JXPCOM_GENH) +#VBoxJXpcom_CLEAN = $(VBOX_JXPCOM_GENH) +VBOX_JXPCOM_GENH = \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_XPCOMImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_GREImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_MozillaImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_XPCOMJavaProxy.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_JavaXPCOMMethods.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_ProfileLock.h + + +else # VBOX_ONLY_SDK +# Nothing yet +endif # VBOX_ONLY_SDK + +# +# Install JAR files +# +INSTALLS += VBoxJXpcom-inst-jar + +VBOX_JXPCOM_JAR = $(VBoxJXpcom-inst-jar_0_OUTDIR)/vboxjxpcom.jar +VBOX_JXPCOM_NSERROR = $(VBOX_JXPCOM_GEN)/java/XPCOMError.java +ifndef VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +VBOX_JXPCOM_GEN = $(VBOX_JXPCOM_TARGET)/jxpcomgen +else +VBOX_JXPCOM_GEN = $(VBOX_JXPCOM_TARGET)/jxpcomgen-idl +endif + +VBoxJXpcom-inst-jar_INST = $(INST_SDK)bindings/xpcom/java/ +VBoxJXpcom-inst-jar_MODE = a+r,u+w +VBoxJXpcom-inst-jar_SOURCES = \ + $(VBOX_JXPCOM_JAR) +VBoxJXpcom-inst-jar_CLEAN = \ + $(VBOX_JXPCOM_JAR) \ + $(VBOX_JXPCOM_NSERROR) \ + $(VBOX_JXPCOM_GEN)/jxpcomgen.list \ + $(VBOX_JXPCOM_GEN)/jxpcomglue.list \ + $(wildcard \ + $(VBOX_JXPCOM_GEN)/java/*.java \ + $(VBOX_JXPCOM_GEN)/java/glue/*.java \ + $(VBOX_JXPCOM_JDEST)/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*/*/*.class \ + ) +VBoxJXpcom-inst-jar_BLDDIRS += $(VBOX_JXPCOM_GEN)/java $(VBOX_JXPCOM_GEN)/java/glue $(VBOX_JXPCOM_GEN)/java/interfaces + +# +# For VBoxJXpcom, not currently used. +# +$(VBOX_JXPCOM_GENH): $$(VBOX_JXPCOM_JAR) + $(call MSG_L1,Generating $@ from $<) + $(QUIET)$(VBOX_JAVAH) -classpath $(VBOX_JXPCOM_JDEST) -d $(VBOX_JXPCOM_JDEST) \ + org.mozilla.xpcom.internal.XPCOMImpl \ + org.mozilla.xpcom.internal.GREImpl \ + org.mozilla.xpcom.internal.MozillaImpl \ + org.mozilla.xpcom.internal.XPCOMJavaProxy \ + org.mozilla.xpcom.ProfileLock \ + org.mozilla.xpcom.internal.JavaXPCOMMethods + +# +# Generate error constants. +# +$(VBOX_JXPCOM_NSERROR): $(VBOX_PATH_XPCOM_SRC)/xpcom/base/nsError.h $(VBOX_JXPCOM_SRC)/tools/gen-nsError.pl | $(VBOX_JXPCOM_GEN)/java/ + $(call MSG_L1,Generating $@) + $(QUIET)perl $(VBOX_JXPCOM_SRC)/tools/gen-nsError.pl < $< > $@ + +ifndef VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +# +# Generate .java interface files from .xidl +# + +$(VBOX_JXPCOM_GEN)/jxpcomgen.list: \ + $(VBOX_XIDL_FILE) \ + $(VBOX_FILESPLIT) \ + $(VBOX_JXPCOM_SRC)/tools/genjifaces.xsl \ + | $(VBOX_JXPCOM_GEN)/java/interfaces/ + $(call MSG_L1,Generating Java interface files) + $(QUIET)$(RM) -f $(wildcard $(VBOX_JXPCOM_GEN)/java/interfaces/*.java) + $(QUIET)$(VBOX_XSLTPROC) \ + -o $(VBOX_JXPCOM_GEN)/java/interfaces/merged.file $(VBOX_JXPCOM_SRC)/tools/genjifaces.xsl $< + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JXPCOM_GEN)/java/interfaces/merged.file $(VBOX_JXPCOM_GEN)/java/interfaces + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/interfaces/*.java > $@ + +else # VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +# +# Generate .java interface files from the XPCOM and VirtualBox IDL files. +# +# Note! There is not a 1:1 relationship between input and output files here, unfortunately. +# Note! VBOX_JXPCOM_NSERROR shares the output directory with us. +# +$(VBOX_JXPCOM_GEN)/jxpcomgen.list: \ + $(VBOX_PATH_SDK)/bindings/xpcom/idl/VirtualBox_XPCOM.idl \ + $$(addprefix $(VBOX_PATH_XPCOM_SRC)/,$$(XPCOM_IDLFILES)) \ + $(VBOX_XPIDL) \ + | $(VBOX_JXPCOM_GEN)/java/ + $(call MSG_L1,Generating XPCOM Java interface files from IDL) + $(QUIET)$(RM) -f $(filter-out %/XPCOMError.java, $(wildcard $(VBOX_JXPCOM_GEN)/java/*.java)) + $(foreach idl, $(VBOX_PATH_SDK)/bindings/xpcom/idl/VirtualBox_XPCOM.idl $(addprefix $(VBOX_PATH_XPCOM_SRC)/,$(XPCOM_IDLFILES))\ + , $(NLTAB)$(QUIET)$(VBOX_XPIDL) -m java $(XPIDL_INCS) -e $(VBOX_JXPCOM_GEN)/java/$(basename $(notdir $(idl))).java $(idl) ) + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/*.java > $@ +endif # VBOX_WITH_JAVA_SUPPORT_IN_XPIDL + +$(VBOX_JXPCOM_GEN)/jxpcomglue.list: \ + $(VBOX_XIDL_FILE) \ + $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl \ + $(VBOX_FILESPLIT) \ + | $(VBOX_JXPCOM_GEN)/java/glue/ + $(call MSG_L1,Generating Java glue files from XIDL) + $(QUIET)$(RM) -f $(wildcard $(VBOX_JXPCOM_GEN)/java/glue/*.java) + $(QUIET)$(VBOX_XSLTPROC) \ + --stringparam filelistonly "" \ + --stringparam G_vboxApiSuffix $(VBOX_API_SUFFIX) \ + --stringparam G_vboxGlueStyle xpcom \ + --stringparam G_vboxDirPrefix "" \ + -o $(VBOX_JXPCOM_GEN)/java/glue/merged.file $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JXPCOM_GEN)/java/glue/merged.file $(VBOX_JXPCOM_GEN)/java/glue/ + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/glue/*.java > $@ + +# +# Compile the all java code into a JAR file. +# +VBOX_JXPCOM_JSRC = $(VBOX_JXPCOM_SRC)/src/org/mozilla/xpcom +VBOX_JXPCOM_JAR_SRC = \ + $(VBOX_JXPCOM_JSRC)/IXPCOM.java \ + $(VBOX_JXPCOM_JSRC)/Mozilla.java \ + $(VBOX_JXPCOM_JSRC)/VersionComparator.java \ + $(VBOX_JXPCOM_JSRC)/GREVersionRange.java \ + $(VBOX_JXPCOM_JSRC)/IAppFileLocProvider.java \ + $(VBOX_JXPCOM_JSRC)/ProfileLock.java \ + $(VBOX_JXPCOM_JSRC)/IGRE.java \ + $(VBOX_JXPCOM_JSRC)/IJavaXPCOMUtils.java \ + $(VBOX_JXPCOM_JSRC)/XPCOMException.java \ + $(VBOX_JXPCOM_JSRC)/IMozilla.java \ + $(VBOX_JXPCOM_JSRC)/XPCOMInitializationException.java \ + $(VBOX_JXPCOM_JSRC)/INIParser.java \ + $(VBOX_JXPCOM_JSRC)/internal/GREImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/JavaXPCOMMethods.java \ + $(VBOX_JXPCOM_JSRC)/internal/MozillaImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMJavaProxyBase.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMJavaProxy.java + +$$(VBOX_JXPCOM_JAR): $(VBOX_JXPCOM_JAR_SRC) $(VBOX_JXPCOM_GEN)/jxpcomgen.list $(VBOX_JXPCOM_GEN)/jxpcomglue.list $(VBOX_JXPCOM_NSERROR) $(VBOX_JXPCOM_MGR) | $$(dir $$@) + $(call MSG_TOOL,javac,$(notdir $@),jxpcomgen.list,) + $(QUIET)$(RM) -Rf $(VBOX_JXPCOM_JDEST) + $(QUIET)$(MKDIR) -p $(VBOX_JXPCOM_JDEST) + $(QUIET)$(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) @$(VBOX_JXPCOM_GEN)/jxpcomgen.list \ + -d $(VBOX_JXPCOM_JDEST) -classpath $(VBOX_JXPCOM_JDEST) + $(call MSG_TOOL,javac,$(notdir $@),...,) + $(QUIET)$(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) \ + $(VBOX_JXPCOM_JAR_SRC) \ + $(VBOX_JXPCOM_NSERROR) \ + @$(VBOX_JXPCOM_GEN)/jxpcomglue.list \ + -d $(VBOX_JXPCOM_JDEST) -classpath $(VBOX_JXPCOM_JDEST) + $(call MSG_LINK,$(notdir $@),$@) + $(QUIET)$(VBOX_JAR) cf $@ -C $(VBOX_JXPCOM_JDEST) . + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/libs/xpcom18a4/java/README.vbox b/src/libs/xpcom18a4/java/README.vbox new file mode 100644 index 00000000..b22acc4d --- /dev/null +++ b/src/libs/xpcom18a4/java/README.vbox @@ -0,0 +1,5 @@ + JavaXPCOM sources (see https://developer.mozilla.org/en/JavaXPCOM) were taken from +:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot, directory extensions/java/xpcom, +Apr 29 2010. + + Imported to VirtualBox codebase in revision . diff --git a/src/libs/xpcom18a4/java/src/MacJawt.mm b/src/libs/xpcom18a4/java/src/MacJawt.mm new file mode 100644 index 00000000..a2d0d3f8 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/MacJawt.mm @@ -0,0 +1,47 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 <jni.h> +#import <JavaVM/jawt_md.h> +#include "prtypes.h" + + +PRUint64 GetPlatformHandle(JAWT_DrawingSurfaceInfo* dsi) +{ + JAWT_MacOSXDrawingSurfaceInfo* dsi_mac = + static_cast<JAWT_MacOSXDrawingSurfaceInfo*> (dsi->platformInfo); + return reinterpret_cast<PRUint64> (dsi_mac->cocoaViewRef); +} diff --git a/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp b/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp new file mode 100644 index 00000000..a78d6c1d --- /dev/null +++ b/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp @@ -0,0 +1,81 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsJavaInterfaces.h" + + +void XXXNeverCalled_javaxpcom() +{ + MOZILLA_NATIVE(initialize) (nsnull, nsnull); + + GRE_NATIVE(initEmbedding) (nsnull, nsnull, nsnull, nsnull, nsnull); + + GRE_NATIVE(termEmbedding) (nsnull, nsnull); + + GRE_NATIVE(lockProfileDirectory) (nsnull, nsnull, nsnull); + + GRE_NATIVE(notifyProfile) (nsnull, nsnull); + + GRE_NATIVE(lockProfileDirectory) (nsnull, nsnull, nsnull); + + GRE_NATIVE(notifyProfile) (nsnull, nsnull); + + XPCOM_NATIVE(initXPCOM) (nsnull, nsnull, nsnull, nsnull); + + XPCOM_NATIVE(shutdownXPCOM) (nsnull, nsnull, nsnull); + + XPCOM_NATIVE(newLocalFile) (nsnull, nsnull, nsnull, nsnull); + + XPCOM_NATIVE(getComponentManager) (nsnull, nsnull); + + XPCOM_NATIVE(getComponentRegistrar) (nsnull, nsnull); + + XPCOM_NATIVE(getServiceManager) (nsnull, nsnull); + + JAVAPROXY_NATIVE(callXPCOMMethod) (nsnull, nsnull, nsnull, nsnull, nsnull); + + JAVAPROXY_NATIVE(finalizeProxy) (nsnull, nsnull, nsnull); + + JAVAPROXY_NATIVE(isSameXPCOMObject) (nsnull, nsnull, nsnull, nsnull); + + LOCKPROXY_NATIVE(release) (nsnull, nsnull, nsnull); + + MOZILLA_NATIVE(getNativeHandleFromAWT) (nsnull, nsnull, nsnull); + + JXUTILS_NATIVE(wrapJavaObject) (nsnull, nsnull, nsnull, nsnull); + + JXUTILS_NATIVE(wrapXPCOMObject) (nsnull, nsnull, nsnull, nsnull); +} diff --git a/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp new file mode 100644 index 00000000..c10bf4c1 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp @@ -0,0 +1,253 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsAppFileLocProviderProxy.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsILocalFile.h" +#include "nsISimpleEnumerator.h" + + +nsAppFileLocProviderProxy::nsAppFileLocProviderProxy(jobject aJavaObject) +{ + mJavaLocProvider = GetJNIEnv()->NewGlobalRef(aJavaObject); +} + +nsAppFileLocProviderProxy::~nsAppFileLocProviderProxy() +{ + GetJNIEnv()->DeleteGlobalRef(mJavaLocProvider); +} + +NS_IMPL_ISUPPORTS2(nsAppFileLocProviderProxy, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + + +// nsIDirectoryServiceProvider + +NS_IMETHODIMP +nsAppFileLocProviderProxy::GetFile(const char* aProp, PRBool* aIsPersistant, + nsIFile** aResult) +{ + // Setup params for calling Java function + JNIEnv* env = GetJNIEnv(); + jstring prop = env->NewStringUTF(aProp); + if (!prop) + return NS_ERROR_OUT_OF_MEMORY; + jbooleanArray persistant = env->NewBooleanArray(1); + if (!persistant) + return NS_ERROR_OUT_OF_MEMORY; + + // Create method ID + jmethodID mid = nsnull; + jclass clazz = env->GetObjectClass(mJavaLocProvider); + if (clazz) { + mid = env->GetMethodID(clazz, "getFile", + "(Ljava/lang/String;[Z)Ljava/io/File;"); + } + if (!mid) + return NS_ERROR_FAILURE; + + // Call Java function + jobject javaFile = nsnull; + javaFile = env->CallObjectMethod(mJavaLocProvider, mid, prop, persistant); + if (javaFile == nsnull || env->ExceptionCheck()) + return NS_ERROR_FAILURE; + + // Set boolean output value + env->GetBooleanArrayRegion(persistant, 0, 1, (jboolean*) aIsPersistant); + + // Set nsIFile result value + nsCOMPtr<nsILocalFile> localFile; + nsresult rv = File_to_nsILocalFile(env, javaFile, getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aResult); + } + + return rv; +} + + +// nsIDirectoryServiceProvider2 + +class DirectoryEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + DirectoryEnumerator(jobjectArray aJavaFileArray) + : mIndex(0) + { + JNIEnv* env = GetJNIEnv(); + mJavaFileArray = static_cast<jobjectArray> + (env->NewGlobalRef(aJavaFileArray)); + mArraySize = env->GetArrayLength(aJavaFileArray); + } + + ~DirectoryEnumerator() + { + GetJNIEnv()->DeleteGlobalRef(mJavaFileArray); + } + + NS_IMETHOD HasMoreElements(PRBool* aResult) + { + if (!mJavaFileArray) { + *aResult = PR_FALSE; + } else { + *aResult = (mIndex < mArraySize); + } + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports** aResult) + { + nsresult rv = NS_ERROR_FAILURE; + + JNIEnv* env = GetJNIEnv(); + jobject javaFile = env->GetObjectArrayElement(mJavaFileArray, mIndex++); + if (javaFile) { + nsCOMPtr<nsILocalFile> localFile; + rv = File_to_nsILocalFile(env, javaFile, getter_AddRefs(localFile)); + env->DeleteLocalRef(javaFile); + + if (NS_SUCCEEDED(rv)) { + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aResult); + } + } + + env->ExceptionClear(); + return NS_ERROR_FAILURE; + } + +private: + jobjectArray mJavaFileArray; + PRUint32 mArraySize; + PRUint32 mIndex; +}; + +NS_IMPL_ISUPPORTS1(DirectoryEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsAppFileLocProviderProxy::GetFiles(const char* aProp, + nsISimpleEnumerator** aResult) +{ + nsresult rv = NS_OK; + + // Setup params for calling Java function + JNIEnv* env = GetJNIEnv(); + jstring prop = env->NewStringUTF(aProp); + if (!prop) + rv = NS_ERROR_OUT_OF_MEMORY; + + // Create method ID + jmethodID mid = nsnull; + if (NS_SUCCEEDED(rv)) { + jclass clazz = env->GetObjectClass(mJavaLocProvider); + if (clazz) { + mid = env->GetMethodID(clazz, "getFiles", + "(Ljava/lang/String;)[Ljava/io/File;"); + env->DeleteLocalRef(clazz); + } + if (!mid) + rv = NS_ERROR_FAILURE; + } + + // Call Java function + jobject javaFileArray = nsnull; + if (NS_SUCCEEDED(rv)) { + javaFileArray = env->CallObjectMethod(mJavaLocProvider, mid, prop); + + // Handle any exception thrown by Java method. + jthrowable exp = env->ExceptionOccurred(); + if (exp) { +#ifdef DEBUG + env->ExceptionDescribe(); +#endif + + // If the exception is an instance of XPCOMException, then get the + // nsresult from the exception instance. Else, default to + // NS_ERROR_FAILURE. + if (env->IsInstanceOf(exp, xpcomExceptionClass)) { + jfieldID fid; + fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J"); + if (fid) { + rv = env->GetLongField(exp, fid); + } else { + rv = NS_ERROR_FAILURE; + } + NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException"); + } else { + rv = NS_ERROR_FAILURE; + } + } else { + // No exception thrown. Check the result. + if (javaFileArray == nsnull) { + rv = NS_ERROR_FAILURE; + } + } + } + + if (NS_SUCCEEDED(rv)) { + // Parse return value + *aResult = new DirectoryEnumerator(static_cast<jobjectArray> + (javaFileArray)); + NS_ADDREF(*aResult); + return NS_OK; + } + + // Handle error conditions + *aResult = nsnull; + env->ExceptionClear(); + return rv; +} + + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +NS_NewAppFileLocProviderProxy(jobject aJavaLocProvider, + nsIDirectoryServiceProvider** aResult) +{ + nsAppFileLocProviderProxy* provider = + new nsAppFileLocProviderProxy(aJavaLocProvider); + if (provider == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(provider); + + *aResult = provider; + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h new file mode 100644 index 00000000..d3b90880 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h @@ -0,0 +1,65 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsAppFileLocProviderProxy_h_ +#define _nsAppFileLocProviderProxy_h_ + +#include "nsIDirectoryService.h" +#include "jni.h" + + +class nsAppFileLocProviderProxy : public nsIDirectoryServiceProvider2 +{ +public: + nsAppFileLocProviderProxy(jobject aJavaLocProvider); + ~nsAppFileLocProviderProxy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + +private: + jobject mJavaLocProvider; +}; + +extern "C" nsresult +NS_NewAppFileLocProviderProxy(jobject aJavaLocProvider, + nsIDirectoryServiceProvider** aResult); + + +#endif //_nsAppFileLocProviderProxy_h_ + diff --git a/src/libs/xpcom18a4/java/src/nsFileStreams.cpp b/src/libs/xpcom18a4/java/src/nsFileStreams.cpp new file mode 100644 index 00000000..435df58b --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsFileStreams.cpp @@ -0,0 +1,475 @@ +/* -*- Mode: C++; 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 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 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 ***** */ + +#if defined(XP_UNIX) || defined(XP_BEOS) +#include <unistd.h> +#elif defined(XP_MAC) +#include <Files.h> +#elif defined(XP_WIN) +#include <windows.h> +#elif defined(XP_OS2) +#define INCL_DOSERRORS +#include <os2.h> +#else +// XXX add necessary include file for ftruncate (or equivalent) +#endif + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include "nsFileStreams.h" +#include "nsILocalFile.h" +#include "nsXPIDLString.h" +#include "prerror.h" +#include "nsCRT.h" +#include "nsInt64.h" +#include "nsIFile.h" + +#define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 + +#if defined(PR_LOGGING) +// +// Log module for nsFileTransport logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=nsFileIO:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +PRLogModuleInfo* gFileIOLog = nsnull; + +#endif /* PR_LOGGING */ + + +//////////////////////////////////////////////////////////////////////////////// +// nsFileStream + +nsFileStream::nsFileStream() + : mFD(nsnull) + , mCloseFD(PR_TRUE) +{ +} + +nsFileStream::~nsFileStream() +{ + if (mCloseFD) + Close(); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream) + +nsresult +nsFileStream::InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent) +{ + NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED); + // + // this file stream is dependent on its parent to keep the + // file descriptor valid. an owning reference to the parent + // prevents the file descriptor from going away prematurely. + // + mFD = fd; + mCloseFD = PR_FALSE; + mParent = parent; + return NS_OK; +} + +nsresult +nsFileStream::Close() +{ + nsresult rv = NS_OK; + if (mFD) { + if (mCloseFD) + if (PR_Close(mFD) == PR_FAILURE) + rv = NS_BASE_STREAM_OSERROR; + mFD = nsnull; + } + return rv; +} + +NS_IMETHODIMP +nsFileStream::Seek(PRInt32 whence, PRInt64 offset) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + nsInt64 cnt = PR_Seek64(mFD, offset, (PRSeekWhence)whence); + if (cnt == nsInt64(-1)) { + return NS_ErrorAccordingToNSPR(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFileStream::Tell(PRInt64 *result) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + nsInt64 cnt = PR_Seek64(mFD, 0, PR_SEEK_CUR); + if (cnt == nsInt64(-1)) { + return NS_ErrorAccordingToNSPR(); + } + *result = cnt; + return NS_OK; +} + +NS_IMETHODIMP +nsFileStream::SetEOF() +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + +#if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_OS2) || defined(XP_BEOS) + // Some system calls require an EOF offset. + PRInt64 offset; + nsresult rv = Tell(&offset); + if (NS_FAILED(rv)) return rv; +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) + if (ftruncate(PR_FileDesc2NativeHandle(mFD), offset) != 0) { + NS_ERROR("ftruncate failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_MAC) + if (::SetEOF(PR_FileDesc2NativeHandle(mFD), offset) != 0) { + NS_ERROR("SetEOF failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_WIN) + if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) { + NS_ERROR("SetEndOfFile failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_OS2) + if (DosSetFileSize((HFILE) PR_FileDesc2NativeHandle(mFD), offset) != NO_ERROR) { + NS_ERROR("DosSetFileSize failed"); + return NS_ERROR_FAILURE; + } +#else + // XXX not implemented +#endif + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsFileInputStream + +NS_IMPL_ISUPPORTS_INHERITED3(nsFileInputStream, + nsFileStream, + nsIInputStream, + nsIFileInputStream, + nsILineInputStream) + +NS_METHOD +nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(aOuter); + + nsFileInputStream* stream = new nsFileInputStream(); + if (stream == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(stream); + nsresult rv = stream->QueryInterface(aIID, aResult); + NS_RELEASE(stream); + return rv; +} + +nsresult +nsFileInputStream::Open(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm) +{ + nsresult rv = NS_OK; + + // If the previous file is open, close it + if (mFD) { + rv = Close(); + if (NS_FAILED(rv)) return rv; + } + + // Open the file + nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile, &rv); + if (NS_FAILED(rv)) return rv; + if (aIOFlags == -1) + aIOFlags = PR_RDONLY; + if (aPerm == -1) + aPerm = 0; + + PRFileDesc* fd; + rv = localFile->OpenNSPRFileDesc(aIOFlags, aPerm, &fd); + if (NS_FAILED(rv)) return rv; + + mFD = fd; + + if (mBehaviorFlags & DELETE_ON_CLOSE) { + // POSIX compatible filesystems allow a file to be unlinked while a + // file descriptor is still referencing the file. since we've already + // opened the file descriptor, we'll try to remove the file. if that + // fails, then we'll just remember the nsIFile and remove it after we + // close the file descriptor. + rv = aFile->Remove(PR_FALSE); + if (NS_FAILED(rv) && !(mBehaviorFlags & REOPEN_ON_REWIND)) { + // If REOPEN_ON_REWIND is not happenin', we haven't saved the file yet + mFile = aFile; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm, + PRInt32 aBehaviorFlags) +{ + NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_TRUE(!mParent, NS_ERROR_ALREADY_INITIALIZED); + + mBehaviorFlags = aBehaviorFlags; + + // If the file will be reopened on rewind, save the info to open the file + if (mBehaviorFlags & REOPEN_ON_REWIND) { + mFile = aFile; + mIOFlags = aIOFlags; + mPerm = aPerm; + } + + return Open(aFile, aIOFlags, aPerm); +} + +NS_IMETHODIMP +nsFileInputStream::Close() +{ + nsresult rv = nsFileStream::Close(); + if (NS_FAILED(rv)) return rv; + if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) { + rv = mFile->Remove(PR_FALSE); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to delete file"); + // If we don't need to save the file for reopening, free it up + if (!(mBehaviorFlags & REOPEN_ON_REWIND)) { + mFile = nsnull; + } + } + return rv; +} + +NS_IMETHODIMP +nsFileInputStream::Available(PRUint32* aResult) +{ + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRInt32 avail = PR_Available(mFD); + if (avail == -1) { + return NS_ErrorAccordingToNSPR(); + } + *aResult = avail; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult) +{ + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRInt32 bytesRead = PR_Read(mFD, aBuf, aCount); + if (bytesRead == -1) { + return NS_ErrorAccordingToNSPR(); + } + // Check if we're at the end of file and need to close + if (mBehaviorFlags & CLOSE_ON_EOF) { + if (bytesRead == 0) { + Close(); + } + } + + *aResult = bytesRead; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::ReadLine(nsACString& aLine, PRBool* aResult) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32* aResult) +{ + // ReadSegments is not implemented because it would be inefficient when + // the writer does not consume all data. If you want to call ReadSegments, + // wrap a BufferedInputStream around the file stream. That will call + // Read(). + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsFileInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + if (!mFD) { + if (mBehaviorFlags & REOPEN_ON_REWIND) { + nsresult rv = Reopen(); + if (NS_FAILED(rv)) { + return rv; + } + } else { + return NS_BASE_STREAM_CLOSED; + } + } + + return nsFileStream::Seek(aWhence, aOffset); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsFileOutputStream + +NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream, + nsFileStream, + nsIOutputStream, + nsIFileOutputStream) + +NS_METHOD +nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(aOuter); + + nsFileOutputStream* stream = new nsFileOutputStream(); + if (stream == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(stream); + nsresult rv = stream->QueryInterface(aIID, aResult); + NS_RELEASE(stream); + return rv; +} + +NS_IMETHODIMP +nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, + PRInt32 behaviorFlags) +{ + NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED); + + nsresult rv; + nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv); + if (NS_FAILED(rv)) return rv; + if (ioFlags == -1) + ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; + if (perm <= 0) + perm = 0664; + + PRFileDesc* fd; + rv = localFile->OpenNSPRFileDesc(ioFlags, perm, &fd); + if (NS_FAILED(rv)) return rv; + + mFD = fd; + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::Close() +{ + return nsFileStream::Close(); +} + +NS_IMETHODIMP +nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Write(mFD, buf, count); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + *result = cnt; + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::Flush(void) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Sync(mFD); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom (see source comment)"); + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +NS_IMETHODIMP +nsFileOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments (see source comment)"); + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +NS_IMETHODIMP +nsFileOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/java/src/nsFileStreams.h b/src/libs/xpcom18a4/java/src/nsFileStreams.h new file mode 100644 index 00000000..7d713fc5 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsFileStreams.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 2; 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) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef nsFileStreams_h__ +#define nsFileStreams_h__ + +#include "nsIFileStreams.h" +#include "nsIFile.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsISeekableStream.h" +#include "nsILineInputStream.h" +#include "nsCOMPtr.h" +#include "prlog.h" +#include "prio.h" + +template<class CharType> class nsLineBuffer; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileStream : public nsISeekableStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISEEKABLESTREAM + + nsFileStream(); + virtual ~nsFileStream(); + + nsresult Close(); + nsresult InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent); + +protected: + PRFileDesc* mFD; + nsCOMPtr<nsISupports> mParent; // strong reference to parent nsFileIO, + // which ensures mFD remains valid. + PRBool mCloseFD; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileInputStream : public nsFileStream, + public nsIFileInputStream, + public nsILineInputStream +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIFILEINPUTSTREAM + NS_DECL_NSILINEINPUTSTREAM + + // Overrided from nsFileStream + NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset); + + nsFileInputStream() : nsFileStream() + { + mBehaviorFlags = 0; + } + virtual ~nsFileInputStream() + { + Close(); + } + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +protected: + /** + * The file being opened. Only stored when DELETE_ON_CLOSE or + * REOPEN_ON_REWIND are true. + */ + nsCOMPtr<nsIFile> mFile; + /** + * The IO flags passed to Init() for the file open. + * Only set for REOPEN_ON_REWIND. + */ + PRInt32 mIOFlags; + /** + * The permissions passed to Init() for the file open. + * Only set for REOPEN_ON_REWIND. + */ + PRInt32 mPerm; + /** + * Flags describing our behavior. See the IDL file for possible values. + */ + PRInt32 mBehaviorFlags; + +protected: + /** + * Internal, called to open a file. Parameters are the same as their + * Init() analogues. + */ + nsresult Open(nsIFile* file, PRInt32 ioFlags, PRInt32 perm); + /** + * Reopen the file (for OPEN_ON_READ only!) + */ + nsresult Reopen() { return Open(mFile, mIOFlags, mPerm); } +}; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileOutputStream : public nsFileStream, + public nsIFileOutputStream +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIOUTPUTSTREAM + NS_DECL_NSIFILEOUTPUTSTREAM + + nsFileOutputStream() : nsFileStream() {} + virtual ~nsFileOutputStream() { nsFileOutputStream::Close(); } + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsFileStreams_h__ diff --git a/src/libs/xpcom18a4/java/src/nsIFileStreams.h b/src/libs/xpcom18a4/java/src/nsIFileStreams.h new file mode 100644 index 00000000..3df02b55 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsIFileStreams.h @@ -0,0 +1,209 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM nsIFileStreams.idl + */ + +#ifndef __gen_nsIFileStreams_h__ +#define __gen_nsIFileStreams_h__ + + +#ifndef __gen_nsIInputStream_h__ +#include "nsIInputStream.h" +#endif + +#ifndef __gen_nsIOutputStream_h__ +#include "nsIOutputStream.h" +#endif + +/* For IDL files that don't want to include root IDL files. */ +#ifndef NS_NO_VTABLE +#define NS_NO_VTABLE +#endif +class nsIFile; /* forward declaration */ + + +/* starting interface: nsIFileInputStream */ +#define NS_IFILEINPUTSTREAM_IID_STR "e3d56a20-c7ec-11d3-8cda-0060b0fc14a3" + +#define NS_IFILEINPUTSTREAM_IID \ + {0xe3d56a20, 0xc7ec, 0x11d3, \ + { 0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3 }} + +/** + * An input stream that allows you to read from a file. + */ +class NS_NO_VTABLE nsIFileInputStream : public nsIInputStream { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILEINPUTSTREAM_IID) + + /** + * @param file file to read from (must QI to nsILocalFile) + * @param ioFlags file open flags listed in prio.h + * @param perm file mode bits listed in prio.h + * @param behaviorFlags flags specifying various behaviors of the class + * (see enumerations in the class) + */ + /* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) = 0; + + /** + * If this is set, the file will be deleted by the time the stream is + * closed. It may be removed before the stream is closed if it is possible + * to delete it and still read from it. + * + * If OPEN_ON_READ is defined, and the file was recreated after the first + * delete, the file will be deleted again when it is closed again. + */ + enum { DELETE_ON_CLOSE = 2 }; + + /** + * If this is set, the file will close automatically when the end of the + * file is reached. + */ + enum { CLOSE_ON_EOF = 4 }; + + /** + * If this is set, the file will be reopened whenever Seek(0) occurs. If + * the file is already open and the seek occurs, it will happen naturally. + * (The file will only be reopened if it is closed for some reason.) + */ + enum { REOPEN_ON_REWIND = 8 }; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIFILEINPUTSTREAM \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags); \ + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIFILEINPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return _to Init(file, ioFlags, perm, behaviorFlags); } \ + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIFILEINPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return !_to ? NS_ERROR_NULL_POINTER : _to->Init(file, ioFlags, perm, behaviorFlags); } \ + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsFileInputStream : public nsIFileInputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEINPUTSTREAM + + nsFileInputStream(); + +private: + ~nsFileInputStream(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsFileInputStream, nsIFileInputStream) + +nsFileInputStream::nsFileInputStream() +{ + /* member initializers and constructor code */ +} + +nsFileInputStream::~nsFileInputStream() +{ + /* destructor code */ +} + +/* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ +NS_IMETHODIMP nsFileInputStream::Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +/* starting interface: nsIFileOutputStream */ +#define NS_IFILEOUTPUTSTREAM_IID_STR "e6f68040-c7ec-11d3-8cda-0060b0fc14a3" + +#define NS_IFILEOUTPUTSTREAM_IID \ + {0xe6f68040, 0xc7ec, 0x11d3, \ + { 0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3 }} + +/** + * An output stream that lets you stream to a file. + */ +class NS_NO_VTABLE nsIFileOutputStream : public nsIOutputStream { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILEOUTPUTSTREAM_IID) + + /** + * @param file - file to write to (must QI to nsILocalFile) + * @param ioFlags - file open flags listed in prio.h + * @param perm - file mode bits listed in prio.h + * @param behaviorFlags flags specifying various behaviors of the class + * (currently none supported) + */ + /* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) = 0; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIFILEOUTPUTSTREAM \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags); + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIFILEOUTPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return _to Init(file, ioFlags, perm, behaviorFlags); } + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIFILEOUTPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return !_to ? NS_ERROR_NULL_POINTER : _to->Init(file, ioFlags, perm, behaviorFlags); } + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsFileOutputStream : public nsIFileOutputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEOUTPUTSTREAM + + nsFileOutputStream(); + +private: + ~nsFileOutputStream(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsFileOutputStream, nsIFileOutputStream) + +nsFileOutputStream::nsFileOutputStream() +{ + /* member initializers and constructor code */ +} + +nsFileOutputStream::~nsFileOutputStream() +{ + /* destructor code */ +} + +/* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ +NS_IMETHODIMP nsFileOutputStream::Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +#endif /* __gen_nsIFileStreams_h__ */ diff --git a/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp new file mode 100644 index 00000000..103f2f37 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp @@ -0,0 +1,557 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsJavaInterfaces.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "nsIComponentRegistrar.h" +#include "nsString.h" +#include "nsISimpleEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIInputStream.h" +#include "nsEnumeratorUtils.h" +#include "nsAppFileLocProviderProxy.h" +#ifndef VBOX +#include "nsXULAppAPI.h" +#endif +#include "nsILocalFile.h" + +#ifdef XP_MACOSX +#include "jawt.h" +#endif + + +#ifdef VBOX +#if 0 +#include "org_mozilla_xpcom_internal_GREImpl.h" +#include "org_mozilla_xpcom_internal_JavaXPCOMMethods.h" +#include "org_mozilla_xpcom_internal_MozillaImpl.h" +#include "org_mozilla_xpcom_internal_XPCOMImpl.h" +#include "org_mozilla_xpcom_internal_XPCOMJavaProxy.h" +#include "org_mozilla_xpcom_ProfileLock.h" +#endif +#include <VBox/com/com.h> +using namespace com; +#include <iprt/initterm.h> +#include <iprt/string.h> +#include <alloca.h> +#endif + +extern "C" NS_EXPORT void JNICALL +MOZILLA_NATIVE(initialize) (JNIEnv* env, jobject) +{ + if (!InitializeJavaGlobals(env)) { + jclass clazz = + env->FindClass("org/mozilla/xpcom/XPCOMInitializationException"); + if (clazz) { + env->ThrowNew(clazz, "Failed to initialize JavaXPCOM"); + } + } +} + +nsresult +InitEmbedding_Impl(JNIEnv* env, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider) +{ + nsresult rv; + + // create an nsILocalFile from given java.io.File + nsCOMPtr<nsILocalFile> libXULDir; + if (aLibXULDirectory) { + rv = File_to_nsILocalFile(env, aLibXULDirectory, getter_AddRefs(libXULDir)); + NS_ENSURE_SUCCESS(rv, rv); + } + nsCOMPtr<nsILocalFile> appDir; + if (aAppDirectory) { + rv = File_to_nsILocalFile(env, aAppDirectory, getter_AddRefs(appDir)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // create nsAppFileLocProviderProxy from given Java object + nsCOMPtr<nsIDirectoryServiceProvider> provider; + if (aAppDirProvider) { + rv = NS_NewAppFileLocProviderProxy(aAppDirProvider, + getter_AddRefs(provider)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // init libXUL +#ifdef VBOX + return 0; +#else + return XRE_InitEmbedding(libXULDir, appDir, provider, nsnull, 0); +#endif +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(initEmbedding) (JNIEnv* env, jobject, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider) +{ + nsresult rv = InitEmbedding_Impl(env, aLibXULDirectory, aAppDirectory, + aAppDirProvider); + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failure in initEmbedding"); + FreeJavaGlobals(env); + } +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(termEmbedding) (JNIEnv *env, jobject) +{ + // Free globals before calling XRE_TermEmbedding(), since we need some + // XPCOM services. + FreeJavaGlobals(env); + +#ifndef VBOX + XRE_TermEmbedding(); +#endif +} +#ifdef VBOX +nsresult +InitXPCOMVBox_Impl(JNIEnv* env, jobject aVBoxBinDirectory) +{ +#if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rv = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +#else + const char *pszHome = nsnull; + const char *jhome = nsnull; + jstring path = nsnull; + + int rv; + jclass clazz; + jmethodID getPathMID; + + if (aVBoxBinDirectory && + (clazz = env->FindClass("java/io/File")) && + (getPathMID = env->GetMethodID(clazz, "getAbsolutePath", + "()Ljava/lang/String;")) + ) + { + path = (jstring)env->CallObjectMethod(aVBoxBinDirectory, getPathMID); + pszHome = jhome = env->GetStringUTFChars(path, nsnull); + } + + if (pszHome == nsnull) + pszHome = getenv("VBOX_PROGRAM_PATH"); + + if (pszHome) { + size_t cchHome = strlen(pszHome); + char *pszExePath = (char *)alloca(cchHome + 32); + memcpy(pszExePath, pszHome, cchHome); + memcpy(pszExePath + cchHome, "/javafake", sizeof("/javafake")); + rv = RTR3InitEx(RTR3INIT_VER_CUR, RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_UNOBTRUSIVE, 0, NULL, pszExePath); + } else { + rv = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + } + + if (jhome) + env->ReleaseStringUTFChars(path, jhome); +#endif + + return com::Initialize(); +} +#endif + +nsresult +InitXPCOM_Impl(JNIEnv* env, jobject aMozBinDirectory, + jobject aAppFileLocProvider, jobject* aResult) +{ + nsresult rv; + // create an nsILocalFile from given java.io.File + nsCOMPtr<nsILocalFile> directory; + if (aMozBinDirectory) { + rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // create nsAppFileLocProviderProxy from given Java object + nsCOMPtr<nsIDirectoryServiceProvider> provider; + if (aAppFileLocProvider) { + rv = NS_NewAppFileLocProviderProxy(aAppFileLocProvider, + getter_AddRefs(provider)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // init XPCOM + nsCOMPtr<nsIServiceManager> servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), directory, provider); + NS_ENSURE_SUCCESS(rv, rv); + + // create Java proxy for service manager returned by NS_InitXPCOM2 + return NativeInterfaceToJavaObject(env, servMan, NS_GET_IID(nsIServiceManager), + nsnull, aResult); +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jobject, jobject aMozBinDirectory, + jobject aAppFileLocProvider) +{ +#ifdef VBOX + nsresult rv = InitXPCOMVBox_Impl(env, aMozBinDirectory); + if (NS_SUCCEEDED(rv)) + return nsnull; +#else + jobject servMan; + nsresult rv = InitXPCOM_Impl(env, aMozBinDirectory, aAppFileLocProvider, + &servMan); + if (NS_SUCCEEDED(rv)) + return servMan; +#endif + + ThrowException(env, rv, "Failure in initXPCOM"); + FreeJavaGlobals(env); + return nsnull; +} + +extern "C" NS_EXPORT void JNICALL +#ifdef VBOX +XPCOM_NATIVE2(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr) +#else +XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr) +#endif +{ +#ifdef VBOX + // Free globals before calling NS_ShutdownXPCOM(), since we need some + // XPCOM services. + //FreeJavaGlobals(env); + //com::Shutdown(); +#else + nsresult rv; + nsIServiceManager* servMgr = nsnull; + if (aServMgr) { + // Get native XPCOM instance + nsISupports* instancePtr = nsnull; + rv = JavaObjectToNativeInterface(env, aServMgr, + NS_GET_IID(nsIServiceManager), (void**) &instancePtr); + NS_ASSERTION(NS_SUCCEEDED(rv) && instancePtr != nsnull, + "Failed to get XPCOM obj for ServiceMgr."); + if (NS_SUCCEEDED(rv)) { + rv = instancePtr->QueryInterface(NS_GET_IID(nsIServiceManager), + (void**) &servMgr); + NS_ASSERTION(NS_SUCCEEDED(rv), "QI for nsIServiceManager failed"); + } + + // Even if we failed to get the matching xpcom object, we don't abort this + // function. Just call NS_ShutdownXPCOM with a null service manager. + } + + // Free globals before calling NS_ShutdownXPCOM(), since we need some + // XPCOM services. + FreeJavaGlobals(env); + + rv = NS_ShutdownXPCOM(servMgr); + if (NS_FAILED(rv)) + ThrowException(env, rv, "NS_ShutdownXPCOM failed"); +#endif +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jobject, jstring aPath, + jboolean aFollowLinks) +{ + // Create a Mozilla string from the jstring + const PRUnichar* buf = nsnull; + if (aPath) { + buf = env->GetStringChars(aPath, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsAutoString path_str(buf); + env->ReleaseStringChars(aPath, buf); + + // Make call to given function + nsCOMPtr<nsILocalFile> file; + nsresult rv = NS_NewLocalFile(path_str, aFollowLinks, getter_AddRefs(file)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, file, NS_GET_IID(nsILocalFile), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in newLocalFile"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +#ifdef VBOX +XPCOM_NATIVE2(getComponentManager) (JNIEnv *env, jobject) +#else +XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jobject) +#endif +{ + // Call XPCOM method + nsCOMPtr<nsIComponentManager> cm; + nsresult rv = NS_GetComponentManager(getter_AddRefs(cm)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, cm, NS_GET_IID(nsIComponentManager), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getComponentManager"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jobject) +{ + // Call XPCOM method + nsCOMPtr<nsIComponentRegistrar> cr; + nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(cr)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, cr, NS_GET_IID(nsIComponentRegistrar), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getComponentRegistrar"); + return nsnull; +} + +#ifdef VBOX +# include <VBox/com/NativeEventQueue.h> +# include <iprt/err.h> + +extern "C" NS_EXPORT jint JNICALL +XPCOM_NATIVE2(waitForEvents) (JNIEnv *env, jobject, jlong aTimeout) +{ + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + return -1; + + int rc = aEventQ->processEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout); + + if (RT_SUCCESS(rc)) + return 0; + + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + return 1; + + return 2; +} +#endif + +extern "C" NS_EXPORT jobject JNICALL +#ifdef VBOX +XPCOM_NATIVE2(getServiceManager) (JNIEnv *env, jobject) +#else +XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jobject) +#endif +{ + // Call XPCOM method + nsCOMPtr<nsIServiceManager> sm; + nsresult rv = NS_GetServiceManager(getter_AddRefs(sm)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, sm, NS_GET_IID(nsIServiceManager), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getServiceManager"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +GRE_NATIVE(lockProfileDirectory) (JNIEnv* env, jobject, jobject aDirectory) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (aDirectory) { + nsCOMPtr<nsILocalFile> profileDir; + rv = File_to_nsILocalFile(env, aDirectory, getter_AddRefs(profileDir)); + + if (NS_SUCCEEDED(rv)) { + nsISupports* lock; +#ifdef VBOX + rv = 0; + lock = 0; +#else + rv = XRE_LockProfileDirectory(profileDir, &lock); +#endif + + if (NS_SUCCEEDED(rv)) { + jclass clazz = + env->FindClass("org/mozilla/xpcom/ProfileLock"); + if (clazz) { + jmethodID mid = env->GetMethodID(clazz, "<init>", "(J)V"); + if (mid) { + return env->NewObject(clazz, mid, reinterpret_cast<jlong>(lock)); + } + } + + // if we get here, then something failed + rv = NS_ERROR_FAILURE; + } + } + } + + ThrowException(env, rv, "Failure in lockProfileDirectory"); + return nsnull; +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(notifyProfile) (JNIEnv *env, jobject) +{ +#ifndef VBOX + XRE_NotifyProfile(); +#endif +} + +#ifdef XP_MACOSX +extern PRUint64 GetPlatformHandle(JAWT_DrawingSurfaceInfo* dsi); +#endif + +extern "C" NS_EXPORT jlong JNICALL +MOZILLA_NATIVE(getNativeHandleFromAWT) (JNIEnv* env, jobject clazz, + jobject widget) +{ + PRUint64 handle = 0; + +#if defined(XP_MACOSX) && !defined(VBOX) + JAWT awt; + awt.version = JAWT_VERSION_1_4; + jboolean result = JAWT_GetAWT(env, &awt); + if (result == JNI_FALSE) + return 0; + + JAWT_DrawingSurface* ds = awt.GetDrawingSurface(env, widget); + if (ds != nsnull) { + jint lock = ds->Lock(ds); + if (!(lock & JAWT_LOCK_ERROR)) { + JAWT_DrawingSurfaceInfo* dsi = ds->GetDrawingSurfaceInfo(ds); + if (dsi) { + handle = GetPlatformHandle(dsi); + ds->FreeDrawingSurfaceInfo(dsi); + } + + ds->Unlock(ds); + } + + awt.FreeDrawingSurface(ds); + } +#else + NS_WARNING("getNativeHandleFromAWT JNI method not implemented"); +#endif + + return handle; +} + +extern "C" NS_EXPORT jlong JNICALL +JXUTILS_NATIVE(wrapJavaObject) (JNIEnv* env, jobject, jobject aJavaObject, + jstring aIID) +{ + nsresult rv; + void* xpcomObject = nsnull; + + if (!aJavaObject || !aIID) { + rv = NS_ERROR_NULL_POINTER; + } else { + const char* str = env->GetStringUTFChars(aIID, nsnull); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + nsID iid; + if (iid.Parse(str)) { + rv = JavaObjectToNativeInterface(env, aJavaObject, iid, &xpcomObject); + if (NS_SUCCEEDED(rv)) { + nsISupports *xpcom_nat_obj = (nsISupports*) xpcomObject; + rv = xpcom_nat_obj->QueryInterface(iid, &xpcomObject); + NS_IF_RELEASE(xpcom_nat_obj); + } + } else { + rv = NS_ERROR_INVALID_ARG; + } + + env->ReleaseStringUTFChars(aIID, str); + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to create XPCOM proxy for Java object"); + } + return reinterpret_cast<jlong>(xpcomObject); +} + +extern "C" NS_EXPORT jobject JNICALL +JXUTILS_NATIVE(wrapXPCOMObject) (JNIEnv* env, jobject, jlong aXPCOMObject, + jstring aIID) +{ + nsresult rv; + jobject javaObject = nsnull; + nsISupports* xpcomObject = reinterpret_cast<nsISupports*>(aXPCOMObject); + + if (!xpcomObject || !aIID) { + rv = NS_ERROR_NULL_POINTER; + } else { + const char* str = env->GetStringUTFChars(aIID, nsnull); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + nsID iid; + if (iid.Parse(str)) { + // XXX Should we be passing something other than NULL for aObjectLoader? + rv = NativeInterfaceToJavaObject(env, xpcomObject, iid, nsnull, + &javaObject); + } else { + rv = NS_ERROR_INVALID_ARG; + } + + env->ReleaseStringUTFChars(aIID, str); + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to create XPCOM proxy for Java object"); + } + return javaObject; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h new file mode 100644 index 00000000..69d2f680 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h @@ -0,0 +1,121 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsJavaInterfaces_h_ +#define _nsJavaInterfaces_h_ + +#include "jni.h" +#include "nscore.h" + +#ifdef VBOX +#define MOZILLA_NATIVE(func) Java_org_mozilla_xpcom_internal_MozillaImpl_##func##Native +#define GRE_NATIVE(func) Java_org_mozilla_xpcom_internal_GREImpl_##func##Native +#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func##Native +#define XPCOM_NATIVE2(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func +#else +#define MOZILLA_NATIVE(func) Java_org_mozilla_xpcom_internal_MozillaImpl_##func +#define GRE_NATIVE(func) Java_org_mozilla_xpcom_internal_GREImpl_##func +#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func +#endif +#define JAVAPROXY_NATIVE(func) \ + Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_##func +#define LOCKPROXY_NATIVE(func) Java_org_mozilla_xpcom_ProfileLock_##func +#define JXUTILS_NATIVE(func) \ + Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_##func + + +extern "C" NS_EXPORT void JNICALL +MOZILLA_NATIVE(initialize) (JNIEnv* env, jobject); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(initEmbedding) (JNIEnv* env, jobject, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(termEmbedding) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +GRE_NATIVE(lockProfileDirectory) (JNIEnv *, jobject, jobject aDirectory); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(notifyProfile) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jobject, jobject aMozBinDirectory, + jobject aAppFileLocProvider); + +extern "C" NS_EXPORT void JNICALL +XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jobject, jstring aPath, + jboolean aFollowLinks); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, + jstring aMethodName, jobjectArray aParams); + +extern "C" NS_EXPORT void JNICALL +JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy); + +extern "C" NS_EXPORT jboolean JNICALL +JAVAPROXY_NATIVE(isSameXPCOMObject) (JNIEnv *env, jclass that, jobject aProxy1, + jobject aProxy2); + +extern "C" NS_EXPORT void JNICALL +LOCKPROXY_NATIVE(release) (JNIEnv *env, jclass that, jlong aLockObject); + +extern "C" NS_EXPORT jlong JNICALL +MOZILLA_NATIVE(getNativeHandleFromAWT) (JNIEnv* env, jobject, jobject widget); + +extern "C" NS_EXPORT jlong JNICALL +JXUTILS_NATIVE(wrapJavaObject) (JNIEnv* env, jobject, jobject aJavaObject, + jstring aIID); + +extern "C" NS_EXPORT jobject JNICALL +JXUTILS_NATIVE(wrapXPCOMObject) (JNIEnv* env, jobject, jlong aXPCOMObject, + jstring aIID); + +#endif // _nsJavaInterfaces_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp b/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp new file mode 100644 index 00000000..a046c8a3 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp @@ -0,0 +1,2020 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsJavaInterfaces.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "jni.h" +#include "xptcall.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsCRT.h" +#include "prmem.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" + +static nsID nullID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + +#ifdef VBOX +#include "nsIThread.h" +static nsresult +NS_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + +#endif + +nsresult +CreateJavaArray(JNIEnv* env, PRUint8 aType, PRUint32 aSize, const nsID& aIID, + jobject* aResult) +{ + jobject array = nsnull; + switch (aType) + { + case nsXPTType::T_I8: + array = env->NewByteArray(aSize); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + array = env->NewShortArray(aSize); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + array = env->NewIntArray(aSize); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + array = env->NewLongArray(aSize); + break; + + case nsXPTType::T_FLOAT: + array = env->NewFloatArray(aSize); + break; + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + array = env->NewDoubleArray(aSize); + break; + + case nsXPTType::T_BOOL: + array = env->NewBooleanArray(aSize); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + array = env->NewCharArray(aSize); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + array = env->NewObjectArray(aSize, stringClass, nsnull); + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ASSERTION(iim, "Failed to get InterfaceInfoManager"); + if (!iim) + return NS_ERROR_FAILURE; + + // Get interface info for given IID + nsCOMPtr<nsIInterfaceInfo> info; + nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(info)); + if (NS_FAILED(rv)) + return rv; + + // Get interface name + const char* iface_name; + rv = info->GetNameShared(&iface_name); + if (NS_FAILED(rv)) + return rv; + + // Create proper Java interface name + nsCAutoString class_name("org/mozilla/interfaces/"); + class_name.AppendASCII(iface_name); + jclass ifaceClass = env->FindClass(class_name.get()); + if (!ifaceClass) + return NS_ERROR_FAILURE; + + array = env->NewObjectArray(aSize, ifaceClass, nsnull); + break; + } + + case nsXPTType::T_VOID: + array = env->NewLongArray(aSize); + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = array; + return NS_OK; +} + +nsresult +GetNativeArrayElement(PRUint8 aType, void* aArray, PRUint32 aIndex, + nsXPTCVariant* aResult) +{ + switch (aType) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + aResult->val.u8 = static_cast<PRUint8*>(aArray)[aIndex]; + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + aResult->val.u16 = static_cast<PRUint16*>(aArray)[aIndex]; + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + aResult->val.u32 = static_cast<PRUint32*>(aArray)[aIndex]; + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + aResult->val.u64 = static_cast<PRUint64*>(aArray)[aIndex]; + break; + + case nsXPTType::T_FLOAT: + aResult->val.f = static_cast<float*>(aArray)[aIndex]; + break; + + case nsXPTType::T_DOUBLE: + aResult->val.d = static_cast<double*>(aArray)[aIndex]; + break; + + case nsXPTType::T_BOOL: + aResult->val.b = static_cast<PRBool*>(aArray)[aIndex]; + break; + + case nsXPTType::T_CHAR: + aResult->val.c = static_cast<char*>(aArray)[aIndex]; + break; + + case nsXPTType::T_WCHAR: + aResult->val.wc = static_cast<PRUnichar*>(aArray)[aIndex]; + break; + + case nsXPTType::T_CHAR_STR: + aResult->val.p = static_cast<char**>(aArray)[aIndex]; + break; + + case nsXPTType::T_WCHAR_STR: + aResult->val.p = static_cast<PRUnichar**>(aArray)[aIndex]; + break; + + case nsXPTType::T_IID: + aResult->val.p = static_cast<nsID**>(aArray)[aIndex]; + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + aResult->val.p = static_cast<nsISupports**>(aArray)[aIndex]; + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + aResult->val.p = static_cast<nsString**>(aArray)[aIndex]; + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + aResult->val.p = static_cast<nsCString**>(aArray)[aIndex]; + break; + + case nsXPTType::T_VOID: + aResult->val.p = static_cast<void**>(aArray)[aIndex]; + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +CreateNativeArray(PRUint8 aType, PRUint32 aSize, void** aResult) +{ + void* array = nsnull; + switch (aType) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + array = PR_Malloc(aSize * sizeof(PRUint8)); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + array = PR_Malloc(aSize * sizeof(PRUint16)); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + array = PR_Malloc(aSize * sizeof(PRUint32)); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + array = PR_Malloc(aSize * sizeof(PRUint64)); + break; + + case nsXPTType::T_FLOAT: + array = PR_Malloc(aSize * sizeof(float)); + break; + + case nsXPTType::T_DOUBLE: + array = PR_Malloc(aSize * sizeof(double)); + break; + + case nsXPTType::T_BOOL: + array = PR_Malloc(aSize * sizeof(PRBool)); + break; + + case nsXPTType::T_CHAR: + array = PR_Malloc(aSize * sizeof(char)); + break; + + case nsXPTType::T_WCHAR: + array = PR_Malloc(aSize * sizeof(PRUnichar)); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + array = PR_Malloc(aSize * sizeof(void*)); + break; + + case nsXPTType::T_VOID: + array = PR_Malloc(aSize * sizeof(void*)); + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = array; + return NS_OK; +} + +/** + * Handle 'in' and 'inout' params. + */ +nsresult +SetupParams(JNIEnv *env, const jobject aParam, PRUint8 aType, PRBool aIsOut, + const nsID& aIID, PRUint8 aArrayType, PRUint32 aArraySize, + PRBool aIsArrayElement, PRUint32 aIndex, nsXPTCVariant &aVariant) +{ + nsresult rv = NS_OK; + + switch (aType) + { + case nsXPTType::T_I8: + { + LOG(("byte\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.i8 = env->CallByteMethod(aParam, byteValueMID); + } else { // 'inout' & 'array' + jbyte value; + if (aParam) { + env->GetByteArrayRegion((jbyteArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.i8 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<PRInt8*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I16: + case nsXPTType::T_U8: // C++ unsigned octet <=> Java short + { + LOG(("short\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jshort value = env->CallShortMethod(aParam, shortValueMID); + if (aType == nsXPTType::T_I16) + aVariant.val.i16 = value; + else + aVariant.val.u8 = value; + } else { // 'inout' & 'array' + jshort value; + if (aParam) { + env->GetShortArrayRegion((jshortArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I16) + aVariant.val.i16 = value; + else + aVariant.val.u8 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I16) + static_cast<PRInt16*>(aVariant.val.p)[aIndex] = value; + else + static_cast<PRUint8*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I32: + case nsXPTType::T_U16: // C++ unsigned short <=> Java int + { + LOG(("int\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jint value = env->CallIntMethod(aParam, intValueMID); + if (aType == nsXPTType::T_I32) + aVariant.val.i32 = value; + else + aVariant.val.u16 = value; + } else { // 'inout' & 'array' + jint value; + if (aParam) { + env->GetIntArrayRegion((jintArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I32) + aVariant.val.i32 = value; + else + aVariant.val.u16 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I32) + static_cast<PRInt32*>(aVariant.val.p)[aIndex] = value; + else + static_cast<PRUint16*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I64: + case nsXPTType::T_U32: // C++ unsigned int <=> Java long + { + LOG(("long\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jlong value = env->CallLongMethod(aParam, longValueMID); + if (aType == nsXPTType::T_I64) + aVariant.val.i64 = value; + else + aVariant.val.u32 = value; + } else { // 'inout' & 'array' + jlong value; + if (aParam) { + env->GetLongArrayRegion((jlongArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I64) + aVariant.val.i64 = value; + else + aVariant.val.u32 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I64) + static_cast<PRInt64*>(aVariant.val.p)[aIndex] = value; + else + static_cast<PRUint32*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_FLOAT: + { + LOG(("float\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.f = env->CallFloatMethod(aParam, floatValueMID); + } else { // 'inout' & 'array' + jfloat value; + if (aParam) { + env->GetFloatArrayRegion((jfloatArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.f = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<float*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + // XXX how do we handle unsigned 64-bit value? + case nsXPTType::T_U64: // C++ unsigned long <=> Java double + case nsXPTType::T_DOUBLE: + { + LOG(("double\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jdouble value = env->CallDoubleMethod(aParam, doubleValueMID); + if (aType == nsXPTType::T_DOUBLE) + aVariant.val.d = value; + else + aVariant.val.u64 = static_cast<PRUint64>(value); + } else { // 'inout' & 'array' + jdouble value; + if (aParam) { + env->GetDoubleArrayRegion((jdoubleArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_DOUBLE) + aVariant.val.d = value; + else + aVariant.val.u64 = static_cast<PRUint64>(value); + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_DOUBLE) + static_cast<double*>(aVariant.val.p)[aIndex] = value; + else + static_cast<PRUint64*>(aVariant.val.p)[aIndex] = + static_cast<PRUint64>(value); + } + } + break; + } + + case nsXPTType::T_BOOL: + { + LOG(("boolean\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.b = env->CallBooleanMethod(aParam, booleanValueMID); + } else { // 'inout' & 'array' + jboolean value; + if (aParam) { + env->GetBooleanArrayRegion((jbooleanArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.b = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<PRBool*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_CHAR: + { + LOG(("char\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.c = env->CallCharMethod(aParam, charValueMID); + } else { // 'inout' & 'array' + jchar value; + if (aParam) { + env->GetCharArrayRegion((jcharArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.c = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<char*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_WCHAR: + { + LOG(("char\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.wc = env->CallCharMethod(aParam, charValueMID); + } else { // 'inout' & 'array' + jchar value; + if (aParam) { + env->GetCharArrayRegion((jcharArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.wc = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<PRUnichar*>(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + LOG(("String\n")); + jstring data = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' & 'array' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + void* buf = nsnull; + if (data) { + jsize uniLength = env->GetStringLength(data); + if (uniLength > 0) { + if (aType == nsXPTType::T_CHAR_STR) { + jsize utf8Length = env->GetStringUTFLength(data); + buf = nsMemory::Alloc((utf8Length + 1) * sizeof(char)); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + char* char_str = static_cast<char*>(buf); + env->GetStringUTFRegion(data, 0, uniLength, char_str); + char_str[utf8Length] = '\0'; + + } else { // if T_WCHAR_STR + buf = nsMemory::Alloc((uniLength + 1) * sizeof(jchar)); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + jchar* jchar_str = static_cast<jchar*>(buf); + env->GetStringRegion(data, 0, uniLength, jchar_str); + jchar_str[uniLength] = '\0'; + } + } else { + // create empty string + buf = nsMemory::Alloc(2); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + ((jchar*)buf)[0] = '\0'; + } + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = buf; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + if (aType == nsXPTType::T_CHAR_STR) { + char* str = static_cast<char*>(buf); + static_cast<char**>(aVariant.val.p)[aIndex] = str; + } else { + PRUnichar* str = static_cast<PRUnichar*>(buf); + static_cast<PRUnichar**>(aVariant.val.p)[aIndex] = str; + } + } + break; + } + + case nsXPTType::T_IID: + { + LOG(("String(IID)\n")); + jstring data = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' & 'array' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + nsID* iid = new nsID; + if (!iid) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + if (data) { + // extract IID string from Java string + const char* str = env->GetStringUTFChars(data, nsnull); + if (!str) { + delete iid; + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // parse string into IID object + iid->Parse(str); + env->ReleaseStringUTFChars(data, str); + } else { + *iid = nullID; + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = iid; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + static_cast<nsID**>(aVariant.val.p)[aIndex] = iid; + } + break; + } + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + LOG(("nsISupports\n")); + jobject java_obj = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + java_obj = (jobject) aParam; + } else if (aParam) { // 'inout' & 'array' + java_obj = (jobject) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + void* xpcom_obj; + if (java_obj) { + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + nsID iid; + if (aIID.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); + } else { + isWeakRef = PR_FALSE; + iid = aIID; + } + + rv = JavaObjectToNativeInterface(env, java_obj, iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + NS_ENSURE_TRUE(xpcom_obj, NS_ERROR_FAILURE); + nsISupports *xpcom_nat_obj = (nsISupports*) xpcom_obj; + rv = xpcom_nat_obj->QueryInterface(iid, &xpcom_obj); + NS_IF_RELEASE(xpcom_nat_obj); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. + if (isWeakRef) { + nsISupports* isupports = (nsISupports*) xpcom_obj; + nsCOMPtr<nsISupportsWeakReference> supportsweak = + do_QueryInterface(isupports); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + NS_RELEASE(isupports); + xpcom_obj = weakref; + NS_ADDREF((nsISupports*) xpcom_obj); + } else { + xpcom_obj = nsnull; + } + } + } else { + xpcom_obj = nsnull; + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = xpcom_obj; + aVariant.SetValIsInterface(); + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + static_cast<void**>(aVariant.val.p)[aIndex] = xpcom_obj; + } + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + LOG(("String\n")); + // Expecting only 'in' and 'in dipper' + NS_PRECONDITION(!aIsOut, "unexpected param descriptor"); + if (aIsOut) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = static_cast<jstring>(aParam); + nsAString* str = jstring_to_nsAString(env, jstr); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + aVariant.val.p = str; + aVariant.SetValIsDOMString(); + break; + } + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + LOG(("StringUTF\n")); + // Expecting only 'in' and 'in dipper' + NS_PRECONDITION(!aIsOut, "unexpected param descriptor"); + if (aIsOut) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = static_cast<jstring>(aParam); + nsACString* str = jstring_to_nsACString(env, jstr); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + aVariant.val.p = str; + if (aType == nsXPTType::T_CSTRING) { + aVariant.SetValIsCString(); + } else { + aVariant.SetValIsUTF8String(); + } + break; + } + + // handle "void *" as an "long" in Java + case nsXPTType::T_VOID: + { + LOG(("long (void*)\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.p = + reinterpret_cast<void*>(env->CallLongMethod(aParam, longValueMID)); + } else { // 'inout' & 'array' + jlong value; + if (aParam) { + env->GetLongArrayRegion((jlongArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.p = reinterpret_cast<void*>(value); + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast<void**>(aVariant.val.p)[aIndex] = + reinterpret_cast<void*>(value); + } + } + break; + } + + case nsXPTType::T_ARRAY: + { + jobject sourceArray = nsnull; + if (!aIsOut) { // 'in' + sourceArray = aParam; + } else if (aParam) { // 'inout' + jobjectArray array = static_cast<jobjectArray>(aParam); + sourceArray = env->GetObjectArrayElement(array, 0); + } + + if (sourceArray) { + rv = CreateNativeArray(aArrayType, aArraySize, &aVariant.val.p); + + for (PRUint32 i = 0; i < aArraySize && NS_SUCCEEDED(rv); i++) { + rv = SetupParams(env, sourceArray, aArrayType, PR_FALSE, aIID, 0, 0, + PR_TRUE, i, aVariant); + } + } + + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val.p; + aVariant.SetPtrIsData(); + } + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + { + NS_PRECONDITION(!aIsArrayElement, "sized string array not supported"); + + LOG(("Sized string\n")); + jstring data = nsnull; + if (!aIsOut) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + PRUint32 length = 0; + if (data) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + length = env->GetStringUTFLength(data); + } else { + length = env->GetStringLength(data); + } + if (length > aArraySize) { + rv = NS_ERROR_ILLEGAL_VALUE; + break; + } + } + + PRUint32 size_of_char = (aType == nsXPTType::T_PSTRING_SIZE_IS) ? + sizeof(char) : sizeof(jchar); + PRUint32 allocLength = (aArraySize + 1) * size_of_char; + void* buf = nsMemory::Alloc(allocLength); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (data) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + const char* str = env->GetStringUTFChars(data, nsnull); + if (!str) { + nsMemory::Free(buf); + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + memcpy(buf, str, length); + env->ReleaseStringUTFChars(data, str); + } else { + jchar* jchar_str = static_cast<jchar*>(buf); + env->GetStringRegion(data, 0, length, jchar_str); + } + } + + aVariant.val.p = buf; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + + break; + } + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +/** + * Does any cleanup from objects created in SetupParams, as well as converting + * any out params to Java. + * + * NOTE: If aInvokeResult is an error condition, then we just do cleanup in + * this function. + */ +nsresult +FinalizeParams(JNIEnv *env, const nsXPTParamInfo &aParamInfo, PRUint8 aType, + nsXPTCVariant &aVariant, const nsID& aIID, + PRBool aIsArrayElement, PRUint8 aArrayType, PRUint32 aArraySize, + PRUint32 aIndex, nsresult aInvokeResult, jobject* aParam) +{ + nsresult rv = NS_OK; + + switch (aType) + { + case nsXPTType::T_I8: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jbyte value = aVariant.val.i8; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(byteClass, byteInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetByteArrayRegion((jbyteArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jshort value = (aType == nsXPTType::T_I16) ? aVariant.val.i16 : + aVariant.val.u8; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(shortClass, shortInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetShortArrayRegion((jshortArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jint value = (aType == nsXPTType::T_I32) ? aVariant.val.i32 : + aVariant.val.u16; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(intClass, intInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetIntArrayRegion((jintArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jlong value = (aType == nsXPTType::T_I64) ? aVariant.val.i64 : + aVariant.val.u32; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(longClass, longInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetLongArrayRegion((jlongArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_FLOAT: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jfloat value = aVariant.val.f; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(floatClass, floatInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetFloatArrayRegion((jfloatArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jdouble value = (aType == nsXPTType::T_DOUBLE) ? aVariant.val.d : + aVariant.val.u64; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(doubleClass, doubleInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetDoubleArrayRegion((jdoubleArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_BOOL: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jboolean value = aVariant.val.b; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(booleanClass, booleanInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetBooleanArrayRegion((jbooleanArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jchar value; + if (aType == nsXPTType::T_CHAR) + value = aVariant.val.c; + else + value = aVariant.val.wc; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(charClass, charInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetCharArrayRegion((jcharArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + // create new string from data + jstring str = nsnull; + if (aVariant.val.p) { + if (aType == nsXPTType::T_CHAR_STR) { + str = env->NewStringUTF((const char*) aVariant.val.p); + } else { + PRUint32 length = nsCRT::strlen((const PRUnichar*) aVariant.val.p); + str = env->NewString((const jchar*) aVariant.val.p, length); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // cleanup + if (aVariant.val.p) + nsMemory::Free(aVariant.val.p); + break; + } + + case nsXPTType::T_IID: + { + nsID* iid = static_cast<nsID*>(aVariant.val.p); + + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + // Create the string from nsID + jstring str = nsnull; + if (iid) { + char iid_str[NSID_LENGTH]; + iid->ToProvidedString(iid_str); + str = env->NewStringUTF(iid_str); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // Ordinarily, we would delete 'iid' here. But we cannot do that until + // we've handled all of the params. See comment in CallXPCOMMethod. + // We can safely delete array elements, though. + if (aIsArrayElement) + delete iid; + + break; + } + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsISupports* xpcom_obj = static_cast<nsISupports*>(aVariant.val.p); + + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + jobject java_obj = nsnull; + if (xpcom_obj) { + // Get matching Java object for given xpcom object + rv = NativeInterfaceToJavaObject(env, xpcom_obj, aIID, nsnull, + &java_obj); + if (NS_FAILED(rv)) + break; + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = java_obj; + } else if (*aParam) { + // put new Java object into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, java_obj); + } + } + + // cleanup + NS_IF_RELEASE(xpcom_obj); + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsString* str = static_cast<nsString*>(aVariant.val.p); + if (NS_SUCCEEDED(aInvokeResult) && aParamInfo.IsDipper()) { + // Create Java string from returned nsString + jstring jstr = nsnull; + if (str && !str->IsVoid()) { + jstr = env->NewString((const jchar*) str->get(), str->Length()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + *aParam = jstr; + } + + // cleanup + if (str) { + delete str; + } + break; + } + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsCString* str = static_cast<nsCString*>(aVariant.val.p); + if (NS_SUCCEEDED(aInvokeResult) && aParamInfo.IsDipper()) { + // Create Java string from returned nsString + jstring jstr = nsnull; + if (str && !str->IsVoid()) { + jstr = env->NewStringUTF((const char*) str->get()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + *aParam = jstr; + } + + // cleanup + if (str) { + delete str; + } + break; + } + + case nsXPTType::T_VOID: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jlong value = reinterpret_cast<jlong>(aVariant.val.p); + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(longClass, longInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetLongArrayRegion((jlongArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_ARRAY: + { + if (aParamInfo.IsOut() && NS_SUCCEEDED(aInvokeResult)) { + // Create Java array from returned native array + jobject jarray = nsnull; + if (aVariant.val.p) { + rv = CreateJavaArray(env, aArrayType, aArraySize, aIID, &jarray); + if (NS_FAILED(rv)) + break; + + nsXPTCVariant var; + for (PRUint32 i = 0; i < aArraySize && NS_SUCCEEDED(rv); i++) { + rv = GetNativeArrayElement(aArrayType, aVariant.val.p, i, &var); + if (NS_SUCCEEDED(rv)) { + rv = FinalizeParams(env, aParamInfo, aArrayType, var, aIID, + PR_TRUE, 0, 0, i, aInvokeResult, &jarray); + } + } + } + + if (aParamInfo.IsRetval()) { + *aParam = jarray; + } else if (*aParam) { + // put new Java array into output array + env->SetObjectArrayElement((jobjectArray) *aParam, 0, jarray); + } + } + + // cleanup + // If this is not an out param or if the invokeResult is a failure case, + // then the array elements have not been cleaned up. Do so now. + if (!aParamInfo.IsOut() || (NS_FAILED(aInvokeResult) && aVariant.val.p)) { + nsXPTCVariant var; + for (PRUint32 i = 0; i < aArraySize; i++) { + rv = GetNativeArrayElement(aArrayType, aVariant.val.p, i, &var); + if (NS_SUCCEEDED(rv)) { + FinalizeParams(env, aParamInfo, aArrayType, var, aIID, PR_TRUE, + 0, 0, i, NS_ERROR_FAILURE, nsnull); + } + } + } + PR_Free(aVariant.val.p); + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + { + NS_PRECONDITION(!aIsArrayElement, "sized string array not supported"); + + if ((aParamInfo.IsOut()) && NS_SUCCEEDED(aInvokeResult)) + { + // create new string from data + jstring str = nsnull; + if (aVariant.val.p) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + PRUint32 len = (aArraySize + 1) * sizeof(char); + char* buf = (char*) nsMemory::Alloc(len); + if (buf) { + memcpy(buf, aVariant.val.p, len); + buf[aArraySize] = '\0'; + str = env->NewStringUTF((const char*) buf); + nsMemory::Free(buf); + } + } else { + str = env->NewString((const jchar*) aVariant.val.p, aArraySize); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval()) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // cleanup + if (aVariant.val.p) + nsMemory::Free(aVariant.val.p); + break; + } + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + // Check for Java exception, but don't overwrite pre-existing error code. + if (NS_SUCCEEDED(rv) && env->ExceptionCheck()) + rv = NS_ERROR_FAILURE; + + return rv; +} + +nsresult +QueryAttributeInfo(nsIInterfaceInfo* aIInfo, const char* aMethodName, + PRBool aCapitalizedAttr, PRUint16* aMethodIndex, + const nsXPTMethodInfo** aMethodInfo) + +{ + nsresult rv = NS_ERROR_FAILURE; + + // An 'attribute' will start with either "get" or "set". But first, + // we check the length, in order to skip over method names that match exactly + // "get" or "set". + if (strlen(aMethodName) > 3) { + if (strncmp("get", aMethodName, 3) == 0) { + char* getterName = strdup(aMethodName + 3); + if (!aCapitalizedAttr) { + getterName[0] = tolower(getterName[0]); + } + rv = aIInfo->GetMethodInfoForName(getterName, aMethodIndex, aMethodInfo); + free(getterName); + } else if (strncmp("set", aMethodName, 3) == 0) { + char* setterName = strdup(aMethodName + 3); + if (!aCapitalizedAttr) { + setterName[0] = tolower(setterName[0]); + } + rv = aIInfo->GetMethodInfoForName(setterName, aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) { + // If this succeeded, GetMethodInfoForName will have returned the + // method info for the 'getter'. We want the 'setter', so increase + // method index by one ('setter' immediately follows the 'getter'), + // and get its method info. + (*aMethodIndex)++; + rv = aIInfo->GetMethodInfo(*aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) { + // Double check that this methodInfo matches the given method. + if (!(*aMethodInfo)->IsSetter() || + strcmp(setterName, (*aMethodInfo)->name) != 0) { + rv = NS_ERROR_FAILURE; + } + } + } + free(setterName); + } + } + + return rv; +} + +/** + * Given an interface info struct and a method name, returns the method info + * and index, if that method exists. + * + * Most method names are lower case. Unfortunately, the method names of some + * interfaces (such as nsIAppShell) start with a capital letter. This function + * will try all of the permutations. + */ +nsresult +QueryMethodInfo(nsIInterfaceInfo* aIInfo, const char* aMethodName, + PRUint16* aMethodIndex, const nsXPTMethodInfo** aMethodInfo) +{ + // Skip over any leading underscores, since these are methods that conflicted + // with existing Java keywords + const char* methodName = aMethodName; + if (methodName[0] == '_') { + methodName++; + } + + // The common case is that the method name is lower case, so we check + // that first. + nsresult rv; + rv = aIInfo->GetMethodInfoForName(methodName, aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) + return rv; + + // If there is no method called <aMethodName>, then maybe it is an + // 'attribute'. + rv = QueryAttributeInfo(aIInfo, methodName, PR_FALSE, aMethodIndex, + aMethodInfo); + if (NS_SUCCEEDED(rv)) + return rv; + + // If we get here, then maybe the method name is capitalized. + char* name = strdup(methodName); + name[0] = toupper(name[0]); + rv = aIInfo->GetMethodInfoForName(name, aMethodIndex, aMethodInfo); + free(name); + if (NS_SUCCEEDED(rv)) + return rv; + + // If there is no method called <aMethodName>, then maybe it is an + // 'attribute'. + rv = QueryAttributeInfo(aIInfo, methodName, PR_TRUE, aMethodIndex, + aMethodInfo); + + return rv; +} + +#ifdef VBOX +#include <nsIExceptionService.h> +#include <iprt/err.h> +#include "nspr.h" + +static void makeErrorMessage(nsresult r, char* msg, size_t msgSize) +{ + bool gotMsg = false; + + if (!gotMsg) + { + nsresult rc; + nsCOMPtr <nsIExceptionService> es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr <nsIExceptionManager> em; + rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr <nsIException> ex; + rc = em->GetCurrentException(getter_AddRefs (ex)); + if (NS_SUCCEEDED (rc) && ex) + { + nsXPIDLCString emsg; + ex->GetMessage(getter_Copies(emsg)); + PR_snprintf(msg, msgSize, "%s", + emsg.get()); + gotMsg = true; + } + } + } + } + + if (!gotMsg) + { + const RTCOMERRMSG* pMsg = RTErrCOMGet(r); + if (strncmp(pMsg->pszMsgFull, "Unknown", 7) != 0) + { + PR_snprintf(msg, msgSize, "%s (%s)", + pMsg->pszMsgFull, pMsg->pszDefine); + gotMsg = true; + } + } + + if (!gotMsg) + { + PR_snprintf(msg, msgSize, "Error 0x%x in module 0x%x", + NS_ERROR_GET_CODE(r), NS_ERROR_GET_MODULE(r)); + } +} +#endif + +/** + * org.mozilla.xpcom.XPCOMJavaProxy.internal.callXPCOMMethod + */ +extern "C" NS_EXPORT jobject JNICALL +JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, + jstring aMethodName, jobjectArray aParams) +{ + nsresult rv; + + // Get native XPCOM instance + void* xpcom_obj; + rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj); + if (NS_FAILED(rv)) { + ThrowException(env, 0, "Failed to get matching XPCOM object"); + return nsnull; + } + JavaXPCOMInstance* inst = static_cast<JavaXPCOMInstance*>(xpcom_obj); + + // Get method info + PRUint16 methodIndex; + const nsXPTMethodInfo* methodInfo; + nsIInterfaceInfo* iinfo = inst->InterfaceInfo(); + const char* methodName = env->GetStringUTFChars(aMethodName, nsnull); + rv = QueryMethodInfo(iinfo, methodName, &methodIndex, &methodInfo); + env->ReleaseStringUTFChars(aMethodName, methodName); + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "GetMethodInfoForName failed"); + return nsnull; + } + +#ifdef DEBUG_JAVAXPCOM + const char* ifaceName; + iinfo->GetNameShared(&ifaceName); + LOG(("===> (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); +#endif + + // Convert the Java params + PRUint8 paramCount = methodInfo->GetParamCount(); + nsXPTCVariant* params = nsnull; + if (paramCount) + { + params = new nsXPTCVariant[paramCount]; + if (!params) { + ThrowException(env, NS_ERROR_OUT_OF_MEMORY, "Can't create params array"); + return nsnull; + } + memset(params, 0, paramCount * sizeof(nsXPTCVariant)); + + PRBool foundDependentParam = PR_FALSE; + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + LOG(("\t Param %d: ", i)); + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + params[i].type = paramInfo.GetType(); + + if (params[i].type.IsDependent() && paramInfo.IsIn()) { + foundDependentParam = PR_TRUE; + continue; + } + + if (paramInfo.IsIn()) { + PRUint8 type = params[i].type.TagPart(); + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE) { + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type, + methodIndex, params, PR_TRUE, iid); + } + + if (NS_SUCCEEDED(rv)) { + jobject param = nsnull; + if (aParams && !paramInfo.IsRetval()) { + param = env->GetObjectArrayElement(aParams, i); + } + rv = SetupParams(env, param, type, paramInfo.IsOut(), iid, 0, 0, + PR_FALSE, 0, params[i]); + } + } else { + LOG(("out/retval\n")); + params[i].ptr = &(params[i].val); + params[i].SetPtrIsData(); + } + } + + // Handle any dependent params by doing a second pass + if (foundDependentParam) { + + for (PRUint8 j = 0; j < paramCount && NS_SUCCEEDED(rv); j++) { + + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(j); + params[j].type = paramInfo.GetType(); + + if (!params[j].type.IsDependent()) + continue; + + if (paramInfo.IsIn()) { + PRUint8 type = params[j].type.TagPart(); + + // is paramater an array or sized string? + PRUint8 arrayType = 0; + PRUint32 arraySize = 0; + PRBool isArray = params[j].type.IsArray(); + PRBool isSizedString = isArray ? PR_FALSE : + type == nsXPTType::T_PSTRING_SIZE_IS || + type == nsXPTType::T_PWSTRING_SIZE_IS; + + if (isArray) { + // get array type + nsXPTType xpttype; + rv = iinfo->GetTypeForParam(methodIndex, ¶mInfo, 1, &xpttype); + if (NS_FAILED(rv)) + break; + arrayType = xpttype.TagPart(); + // IDL 'octet' arrays are not 'promoted' to short, but kept as 'byte'; + // therefore, treat as a signed 8bit value + if (arrayType == nsXPTType::T_U8) + arrayType = nsXPTType::T_I8; + } + + if (isArray || isSizedString) { + // get size of array or string + PRUint8 argnum; + rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, ¶mInfo, 0, + &argnum); + if (NS_FAILED(rv)) + break; + arraySize = params[argnum].val.u32; + } + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE_IS || + (type == nsXPTType::T_ARRAY && + (arrayType == nsXPTType::T_INTERFACE || + arrayType == nsXPTType::T_INTERFACE_IS))) + { + PRUint8 paramType = type == nsXPTType::T_ARRAY ? arrayType : type; + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, paramType, + methodIndex, params, PR_TRUE, iid); + } + + if (NS_SUCCEEDED(rv)) { + jobject param = nsnull; + if (aParams && !paramInfo.IsRetval()) { + param = env->GetObjectArrayElement(aParams, j); + } + rv = SetupParams(env, param, type, paramInfo.IsOut(), iid, arrayType, + arraySize, PR_FALSE, 0, params[j]); + } + } + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "SetupParams failed"); + return nsnull; + } + } + + // Call the XPCOM method + const nsIID* iid; + iinfo->GetIIDShared(&iid); + nsISupports* realObject; + rv = inst->GetInstance()->QueryInterface(*iid, (void**) &realObject); + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to get real XPCOM object"); + return nsnull; + } + nsresult invokeResult = NS_InvokeByIndex(realObject, methodIndex, + paramCount, params); + NS_RELEASE(realObject); + + // Clean up params + jobject result = nsnull; + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + PRUint8 type = paramInfo.GetType().TagPart(); + + // is paramater an array or sized string? + PRUint8 arrayType = 0; + PRUint32 arraySize = 0; + PRBool isArray = params[i].type.IsArray(); + PRBool isSizedString = isArray ? PR_FALSE : + type == nsXPTType::T_PSTRING_SIZE_IS || + type == nsXPTType::T_PWSTRING_SIZE_IS; + + if (isArray) { + // get array type + nsXPTType array_xpttype; + rv = iinfo->GetTypeForParam(methodIndex, ¶mInfo, 1, &array_xpttype); + if (NS_FAILED(rv)) + break; + arrayType = array_xpttype.TagPart(); + // IDL 'octet' arrays are not 'promoted' to short, but kept as 'byte'; + // therefore, treat as a signed 8bit value + if (arrayType == nsXPTType::T_U8) + arrayType = nsXPTType::T_I8; + } + + if (isArray || isSizedString) { + // get size of array + PRUint8 argnum; + rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, ¶mInfo, 0, + &argnum); + if (NS_FAILED(rv)) + break; + arraySize = params[argnum].val.u32; + } + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE || type == nsXPTType::T_INTERFACE_IS || + (type == nsXPTType::T_ARRAY && (arrayType == nsXPTType::T_INTERFACE || + arrayType == nsXPTType::T_INTERFACE_IS))) + { + PRUint8 paramType = type == nsXPTType::T_ARRAY ? arrayType : type; + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, paramType, + methodIndex, params, PR_TRUE, iid); + if (NS_FAILED(rv)) + break; + } + + jobject* javaElement; + jobject element = nsnull; + if (!paramInfo.IsRetval()) { + element = env->GetObjectArrayElement(aParams, i); + javaElement = &element; + } else { + javaElement = &result; + } + rv = FinalizeParams(env, paramInfo, type, params[i], iid, PR_FALSE, + arrayType, arraySize, 0, invokeResult, javaElement); + } + + // Normally, we would delete any created nsID object in the above loop. + // However, GetIIDForMethodParam may need some of the nsID params when it's + // looking for the IID of an INTERFACE_IS. Therefore, we can't delete it + // until we've gone through the 'Finalize' loop once and created the result. + for (PRUint8 j = 0; j < paramCount; j++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(j); + const nsXPTType &type = paramInfo.GetType(); + if (type.TagPart() == nsXPTType::T_IID) { + nsID* iid = (nsID*) params[j].val.p; + delete iid; + } + } + + if (params) { + delete params; + } + + // If the XPCOM method invocation failed, we don't immediately throw an + // exception and return so that we can clean up any parameters. + if (NS_FAILED(invokeResult)) { + nsCAutoString message("The function \""); + message.AppendASCII(methodInfo->GetName()); + message.AppendLiteral("\" returned an error condition"); +#ifdef VBOX + char vboxMsg[1024]; + message.AppendLiteral(": \""); + makeErrorMessage(invokeResult, vboxMsg, sizeof vboxMsg); + message.AppendASCII(vboxMsg); + message.AppendLiteral("\""); +#endif + ThrowException(env, invokeResult, message.get()); + } + if (NS_FAILED(rv)) { + ThrowException(env, rv, "FinalizeParams failed"); + return nsnull; + } + + LOG(("<=== (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); + return result; +} + +nsresult +GetNewOrUsedJavaWrapper(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + // Get the root nsISupports of the xpcom object + nsresult rv; + nsCOMPtr<nsISupports> rootObject = do_QueryInterface(aXPCOMObject, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Get associated Java object from hash table + rv = gNativeToJavaProxyMap->Find(env, rootObject, aIID, aResult); + NS_ENSURE_SUCCESS(rv, rv); + if (*aResult) + return NS_OK; + + // No Java object is associated with the given XPCOM object, so we + // create a Java proxy. + + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ASSERTION(iim, "Failed to get InterfaceInfoManager"); + if (!iim) + return NS_ERROR_FAILURE; + + // Get interface info for class + nsCOMPtr<nsIInterfaceInfo> info; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(info)); + if (NS_FAILED(rv)) + return rv; + + // Wrap XPCOM object (addrefs rootObject) + JavaXPCOMInstance* inst = new JavaXPCOMInstance(rootObject, info); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + // Get interface name + const char* iface_name; + rv = info->GetNameShared(&iface_name); + + if (NS_SUCCEEDED(rv)) { + jobject java_obj = nsnull; + + // Create proper Java interface name + nsCAutoString class_name("org.mozilla.interfaces."); + class_name.AppendASCII(iface_name); + jclass ifaceClass = FindClassInLoader(env, aObjectLoader, class_name.get()); + + if (ifaceClass) { + java_obj = env->CallStaticObjectMethod(xpcomJavaProxyClass, + createProxyMID, ifaceClass, + reinterpret_cast<jlong>(inst)); + if (env->ExceptionCheck()) + java_obj = nsnull; + } + + if (java_obj) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ CreateJavaProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + java_obj), + (PRUint32) rootObject, iid_str)); + PR_Free(iid_str); +#endif + + // Associate XPCOM object with Java proxy + rv = gNativeToJavaProxyMap->Add(env, rootObject, aIID, java_obj); + if (NS_SUCCEEDED(rv)) { + *aResult = java_obj; + return NS_OK; + } + } else { + rv = NS_ERROR_FAILURE; + } + } + + // If there was an error, clean up. + delete inst; + return rv; +} + +nsresult +GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + jlong xpcom_obj = env->CallStaticLongMethod(xpcomJavaProxyClass, + getNativeXPCOMInstMID, aJavaObject); + + if (!xpcom_obj || env->ExceptionCheck()) { + return NS_ERROR_FAILURE; + } + + *aResult = reinterpret_cast<void*>(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + JavaXPCOMInstance* inst = static_cast<JavaXPCOMInstance*>(*aResult); + nsIID* iid; + inst->InterfaceInfo()->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< GetXPCOMInstFromProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaObject), + (PRUint32) inst->GetInstance(), iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + return NS_OK; +} + +/** + * org.mozilla.xpcom.internal.XPCOMJavaProxy.finalizeProxy + */ +extern "C" NS_EXPORT void JNICALL +JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy) +{ +#ifdef DEBUG_JAVAXPCOM + PRUint32 xpcom_addr = 0; +#endif + + // Due to Java's garbage collection, this finalize statement may get called + // after FreeJavaGlobals(). So check to make sure that everything is still + // initialized. + if (gJavaXPCOMLock) { + nsAutoLock lock(gJavaXPCOMLock); + + // If may be possible for the lock to be acquired here when FreeGlobals is + // in the middle of running. If so, then this thread will sleep until + // FreeGlobals releases its lock. At that point, we resume this thread + // here, but JavaXPCOM may no longer be initialized. So we need to check + // that everything is legit after acquiring the lock. + if (gJavaXPCOMInitialized) { + // Get native XPCOM instance + void* xpcom_obj; + nsresult rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj); + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst = static_cast<JavaXPCOMInstance*>(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + xpcom_addr = reinterpret_cast<PRUint32>(inst->GetInstance()); +#endif + nsIID* iid; + rv = inst->InterfaceInfo()->GetInterfaceIID(&iid); + if (NS_SUCCEEDED(rv)) { + rv = gNativeToJavaProxyMap->Remove(env, inst->GetInstance(), *iid); + nsMemory::Free(iid); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to RemoveJavaProxy"); + // Release gJavaXPCOMLock before deleting inst (see bug 340022) + lock.unlock(); + delete inst; + } + } + } + +#ifdef DEBUG_JAVAXPCOM + LOG(("- Finalize (Java=%08x | XPCOM=%08x)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaProxy), + xpcom_addr)); +#endif +} + +/** + * org.mozilla.xpcom.XPCOMJavaProxy.isSameXPCOMObject + */ +extern "C" NS_EXPORT jboolean JNICALL +JAVAPROXY_NATIVE(isSameXPCOMObject) (JNIEnv *env, jclass that, + jobject aProxy1, jobject aProxy2) +{ + void* xpcom_obj1; + nsresult rv = GetXPCOMInstFromProxy(env, aProxy1, &xpcom_obj1); + if (NS_SUCCEEDED(rv)) { + void* xpcom_obj2; + rv = GetXPCOMInstFromProxy(env, aProxy2, &xpcom_obj2); + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst1 = static_cast<JavaXPCOMInstance*>(xpcom_obj1); + JavaXPCOMInstance* inst2 = static_cast<JavaXPCOMInstance*>(xpcom_obj2); + if (inst1->GetInstance() == inst2->GetInstance()) { + return JNI_TRUE; + } + } + } + return JNI_FALSE; +} + +/** + * org.mozilla.xpcom.ProfileLock.release + */ +extern "C" NS_EXPORT void JNICALL +LOCKPROXY_NATIVE(release) (JNIEnv *env, jclass that, jlong aLockObject) +{ + // Need to release object on the main thread. + nsresult rv = NS_ERROR_FAILURE; +#ifdef VBOX + rv = NS_ProxyRelease(do_GetMainThreadQueue().get(), reinterpret_cast<nsISupports*>(aLockObject)); +#else + nsCOMPtr<nsIThread> thread = do_GetMainThread(); + if (thread) { + rv = NS_ProxyRelease(thread, reinterpret_cast<nsISupports*>(aLockObject)); + } +#endif + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaWrapper.h b/src/libs/xpcom18a4/java/src/nsJavaWrapper.h new file mode 100644 index 00000000..c441a41c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaWrapper.h @@ -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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsJavaWrapper_h_ +#define _nsJavaWrapper_h_ + +#include "jni.h" +#include "nsISupports.h" + + +/** + * Finds the associated Java wraper for the given XPCOM object and IID. If no + * such Java wrapper exists, then a new one is created. + * + * @param env Java environment pointer + * @param aXPCOMObject XPCOM object for which to find/create Java wrapper + * @param aIID desired interface IID for Java wrapper + * @param aObjectLoader Java wrapper whose class loader we use for finding + * classes; can be null + * @param aResult on success, holds reference to Java wrapper + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult GetNewOrUsedJavaWrapper(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult); + +/** + * Returns the XPCOM object for which the given Java proxy was created. + * + * @param env pointer to Java context + * @param aJavaObject a Java proxy created by CreateJavaProxy() + * @param aResult on exit, holds pointer to XPCOM instance + * + * @return NS_OK if the XPCOM object was successfully retrieved; + * any other value denotes an error condition. + */ +nsresult GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, + void** aResult); + +#endif // _nsJavaWrapper_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp new file mode 100644 index 00000000..f91fdd83 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp @@ -0,0 +1,1084 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaWrapper.h" +#include "jni.h" +#include "nsIInterfaceInfoManager.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" +#ifdef VBOX +#ifndef NS_INT32_TO_PTR +#define NS_INT32_TO_PTR(x) ((void *)((char *)0 + (x))) +#endif +#endif + + +/* Java JNI globals */ + +JavaVM* gCachedJVM = nsnull; + +jclass systemClass = nsnull; +jclass booleanClass = nsnull; +jclass charClass = nsnull; +jclass byteClass = nsnull; +jclass shortClass = nsnull; +jclass intClass = nsnull; +jclass longClass = nsnull; +jclass floatClass = nsnull; +jclass doubleClass = nsnull; +jclass stringClass = nsnull; +jclass nsISupportsClass = nsnull; +jclass xpcomExceptionClass = nsnull; +jclass xpcomJavaProxyClass = nsnull; +jclass weakReferenceClass = nsnull; +jclass javaXPCOMUtilsClass = nsnull; + +jmethodID hashCodeMID = nsnull; +jmethodID booleanValueMID = nsnull; +jmethodID booleanInitMID = nsnull; +jmethodID charValueMID = nsnull; +jmethodID charInitMID = nsnull; +jmethodID byteValueMID = nsnull; +jmethodID byteInitMID = nsnull; +jmethodID shortValueMID = nsnull; +jmethodID shortInitMID = nsnull; +jmethodID intValueMID = nsnull; +jmethodID intInitMID = nsnull; +jmethodID longValueMID = nsnull; +jmethodID longInitMID = nsnull; +jmethodID floatValueMID = nsnull; +jmethodID floatInitMID = nsnull; +jmethodID doubleValueMID = nsnull; +jmethodID doubleInitMID = nsnull; +jmethodID createProxyMID = nsnull; +jmethodID isXPCOMJavaProxyMID = nsnull; +jmethodID getNativeXPCOMInstMID = nsnull; +jmethodID weakReferenceConstructorMID = nsnull; +jmethodID getReferentMID = nsnull; +jmethodID clearReferentMID = nsnull; +jmethodID findClassInLoaderMID = nsnull; + +#ifdef DEBUG_JAVAXPCOM +jmethodID getNameMID = nsnull; +jmethodID proxyToStringMID = nsnull; +#endif + +NativeToJavaProxyMap* gNativeToJavaProxyMap = nsnull; +JavaToXPTCStubMap* gJavaToXPTCStubMap = nsnull; + +PRBool gJavaXPCOMInitialized = PR_FALSE; +PRLock* gJavaXPCOMLock = nsnull; + +static const char* kJavaKeywords[] = { + "abstract", "default" , "if" , "private" , "throw" , + "boolean" , "do" , "implements", "protected" , "throws" , + "break" , "double" , "import", "public" , "transient" , + "byte" , "else" , "instanceof", "return" , "try" , + "case" , "extends" , "int" , "short" , "void" , + "catch" , "final" , "interface" , "static" , "volatile" , + "char" , "finally" , "long" , "super" , "while" , + "class" , "float" , "native" , "switch" , + "const" , "for" , "new" , "synchronized", + "continue", "goto" , "package" , "this" , + /* added in Java 1.2 */ + "strictfp", + /* added in Java 1.4 */ + "assert" , + /* added in Java 5.0 */ + "enum" , + /* Java constants */ + "true" , "false" , "null" , + /* java.lang.Object methods * + * - don't worry about "toString", since it does the same thing * + * as Object's "toString" */ + "clone" , "equals" , "finalize" , "getClass" , "hashCode" , + "notify" , "notifyAll", /*"toString" ,*/ "wait" +}; + +nsTHashtable<nsDepCharHashKey>* gJavaKeywords = nsnull; + + +/****************************** + * InitializeJavaGlobals + ******************************/ +PRBool +InitializeJavaGlobals(JNIEnv *env) +{ + if (gJavaXPCOMInitialized) + return PR_TRUE; + + // Save pointer to JavaVM, which is valid across threads. + jint rc = env->GetJavaVM(&gCachedJVM); + if (rc != 0) { + NS_WARNING("Failed to get JavaVM"); + goto init_error; + } + + jclass clazz; + if (!(clazz = env->FindClass("java/lang/System")) || + !(systemClass = (jclass) env->NewGlobalRef(clazz)) || + !(hashCodeMID = env->GetStaticMethodID(clazz, "identityHashCode", + "(Ljava/lang/Object;)I"))) + { + NS_WARNING("Problem creating java.lang.System globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Boolean")) || + !(booleanClass = (jclass) env->NewGlobalRef(clazz)) || + !(booleanValueMID = env->GetMethodID(clazz, "booleanValue", "()Z")) || + !(booleanInitMID = env->GetMethodID(clazz, "<init>", "(Z)V"))) + { + NS_WARNING("Problem creating java.lang.Boolean globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Character")) || + !(charClass = (jclass) env->NewGlobalRef(clazz)) || + !(charValueMID = env->GetMethodID(clazz, "charValue", "()C")) || + !(charInitMID = env->GetMethodID(clazz, "<init>", "(C)V"))) + { + NS_WARNING("Problem creating java.lang.Character globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Byte")) || + !(byteClass = (jclass) env->NewGlobalRef(clazz)) || + !(byteValueMID = env->GetMethodID(clazz, "byteValue", "()B")) || + !(byteInitMID = env->GetMethodID(clazz, "<init>", "(B)V"))) + { + NS_WARNING("Problem creating java.lang.Byte globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Short")) || + !(shortClass = (jclass) env->NewGlobalRef(clazz)) || + !(shortValueMID = env->GetMethodID(clazz, "shortValue", "()S")) || + !(shortInitMID = env->GetMethodID(clazz, "<init>", "(S)V"))) + { + NS_WARNING("Problem creating java.lang.Short globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Integer")) || + !(intClass = (jclass) env->NewGlobalRef(clazz)) || + !(intValueMID = env->GetMethodID(clazz, "intValue", "()I")) || + !(intInitMID = env->GetMethodID(clazz, "<init>", "(I)V"))) + { + NS_WARNING("Problem creating java.lang.Integer globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Long")) || + !(longClass = (jclass) env->NewGlobalRef(clazz)) || + !(longValueMID = env->GetMethodID(clazz, "longValue", "()J")) || + !(longInitMID = env->GetMethodID(clazz, "<init>", "(J)V"))) + { + NS_WARNING("Problem creating java.lang.Long globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Float")) || + !(floatClass = (jclass) env->NewGlobalRef(clazz)) || + !(floatValueMID = env->GetMethodID(clazz, "floatValue", "()F")) || + !(floatInitMID = env->GetMethodID(clazz, "<init>", "(F)V"))) + { + NS_WARNING("Problem creating java.lang.Float globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Double")) || + !(doubleClass = (jclass) env->NewGlobalRef(clazz)) || + !(doubleValueMID = env->GetMethodID(clazz, "doubleValue", "()D")) || + !(doubleInitMID = env->GetMethodID(clazz, "<init>", "(D)V"))) + { + NS_WARNING("Problem creating java.lang.Double globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/String")) || + !(stringClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating java.lang.String globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/interfaces/nsISupports")) || + !(nsISupportsClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating org.mozilla.interfaces.nsISupports globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/XPCOMException")) || + !(xpcomExceptionClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.XPCOMException globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMJavaProxy")) || + !(xpcomJavaProxyClass = (jclass) env->NewGlobalRef(clazz)) || + !(createProxyMID = env->GetStaticMethodID(clazz, "createProxy", + "(Ljava/lang/Class;J)Ljava/lang/Object;")) || + !(isXPCOMJavaProxyMID = env->GetStaticMethodID(clazz, "isXPCOMJavaProxy", + "(Ljava/lang/Object;)Z")) || + !(getNativeXPCOMInstMID = env->GetStaticMethodID(xpcomJavaProxyClass, + "getNativeXPCOMInstance", + "(Ljava/lang/Object;)J"))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.internal.XPCOMJavaProxy globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/ref/WeakReference")) || + !(weakReferenceClass = (jclass) env->NewGlobalRef(clazz)) || + !(weakReferenceConstructorMID = env->GetMethodID(weakReferenceClass, + "<init>","(Ljava/lang/Object;)V")) || + !(getReferentMID = env->GetMethodID(weakReferenceClass, + "get", "()Ljava/lang/Object;")) || + !(clearReferentMID = env->GetMethodID(weakReferenceClass, + "clear", "()V"))) + { + NS_WARNING("Problem creating java.lang.ref.WeakReference globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/internal/JavaXPCOMMethods")) || + !(javaXPCOMUtilsClass = (jclass) env->NewGlobalRef(clazz)) || + !(findClassInLoaderMID = env->GetStaticMethodID(clazz, + "findClassInLoader", + "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Class;"))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.internal.JavaXPCOMMethods globals"); + goto init_error; + } + +#ifdef DEBUG_JAVAXPCOM + if (!(clazz = env->FindClass("java/lang/Class")) || + !(getNameMID = env->GetMethodID(clazz, "getName","()Ljava/lang/String;"))) + { + NS_WARNING("Problem creating java.lang.Class globals"); + goto init_error; + } + + if (!(proxyToStringMID = env->GetStaticMethodID(xpcomJavaProxyClass, + "proxyToString", + "(Ljava/lang/Object;)Ljava/lang/String;"))) + { + NS_WARNING("Problem creating proxyToString global"); + goto init_error; + } +#endif + + gNativeToJavaProxyMap = new NativeToJavaProxyMap(); + if (!gNativeToJavaProxyMap || NS_FAILED(gNativeToJavaProxyMap->Init())) { + NS_WARNING("Problem creating NativeToJavaProxyMap"); + goto init_error; + } + gJavaToXPTCStubMap = new JavaToXPTCStubMap(); + if (!gJavaToXPTCStubMap || NS_FAILED(gJavaToXPTCStubMap->Init())) { + NS_WARNING("Problem creating JavaToXPTCStubMap"); + goto init_error; + } + + { + nsresult rv = NS_OK; + PRUint32 size = NS_ARRAY_LENGTH(kJavaKeywords); + gJavaKeywords = new nsTHashtable<nsDepCharHashKey>(); + if (!gJavaKeywords || NS_FAILED(gJavaKeywords->Init(size))) { + NS_WARNING("Failed to init JavaKeywords HashSet"); + goto init_error; + } + for (PRUint32 i = 0; i < size && NS_SUCCEEDED(rv); i++) { + if (!gJavaKeywords->PutEntry(kJavaKeywords[i])) { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + if (NS_FAILED(rv)) { + NS_WARNING("Failed to populate JavaKeywords hash"); + goto init_error; + } + } + + gJavaXPCOMLock = PR_NewLock(); + gJavaXPCOMInitialized = PR_TRUE; + return PR_TRUE; + +init_error: + // If we encounter an error during initialization, then free any globals that + // were allocated, and return false. + FreeJavaGlobals(env); + return PR_FALSE; +} + +/************************* + * FreeJavaGlobals + *************************/ +void +FreeJavaGlobals(JNIEnv* env) +{ + PRLock* tempLock = nsnull; + if (gJavaXPCOMLock) { + PR_Lock(gJavaXPCOMLock); + + // null out global lock so no one else can use it + tempLock = gJavaXPCOMLock; + gJavaXPCOMLock = nsnull; + } + + gJavaXPCOMInitialized = PR_FALSE; + + // Free the mappings first, since that process depends on some of the Java + // globals that are freed later. + if (gNativeToJavaProxyMap) { + gNativeToJavaProxyMap->Destroy(env); + delete gNativeToJavaProxyMap; + gNativeToJavaProxyMap = nsnull; + } + if (gJavaToXPTCStubMap) { + gJavaToXPTCStubMap->Destroy(); + delete gJavaToXPTCStubMap; + gJavaToXPTCStubMap = nsnull; + } + + // Free remaining Java globals + if (systemClass) { + env->DeleteGlobalRef(systemClass); + systemClass = nsnull; + } + if (booleanClass) { + env->DeleteGlobalRef(booleanClass); + booleanClass = nsnull; + } + if (charClass) { + env->DeleteGlobalRef(charClass); + charClass = nsnull; + } + if (byteClass) { + env->DeleteGlobalRef(byteClass); + byteClass = nsnull; + } + if (shortClass) { + env->DeleteGlobalRef(shortClass); + shortClass = nsnull; + } + if (intClass) { + env->DeleteGlobalRef(intClass); + intClass = nsnull; + } + if (longClass) { + env->DeleteGlobalRef(longClass); + longClass = nsnull; + } + if (floatClass) { + env->DeleteGlobalRef(floatClass); + floatClass = nsnull; + } + if (doubleClass) { + env->DeleteGlobalRef(doubleClass); + doubleClass = nsnull; + } + if (stringClass) { + env->DeleteGlobalRef(stringClass); + stringClass = nsnull; + } + if (nsISupportsClass) { + env->DeleteGlobalRef(nsISupportsClass); + nsISupportsClass = nsnull; + } + if (xpcomExceptionClass) { + env->DeleteGlobalRef(xpcomExceptionClass); + xpcomExceptionClass = nsnull; + } + if (xpcomJavaProxyClass) { + env->DeleteGlobalRef(xpcomJavaProxyClass); + xpcomJavaProxyClass = nsnull; + } + if (weakReferenceClass) { + env->DeleteGlobalRef(weakReferenceClass); + weakReferenceClass = nsnull; + } + + if (gJavaKeywords) { + delete gJavaKeywords; + gJavaKeywords = nsnull; + } + + if (tempLock) { + PR_Unlock(tempLock); + PR_DestroyLock(tempLock); + } +} + + +/************************************** + * Java<->XPCOM object mappings + **************************************/ + +// NativeToJavaProxyMap: The common case is that each XPCOM object will have +// one Java proxy. But there are instances where there will be multiple Java +// proxies for a given XPCOM object, each representing a different interface. +// So we optimize the common case by using a hash table. Then, if there are +// multiple Java proxies, we cycle through the linked list, comparing IIDs. + +nsresult +NativeToJavaProxyMap::Init() +{ + mHashTable = PL_NewDHashTable(PL_DHashGetStubOps(), nsnull, + sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +PLDHashOperator +DestroyJavaProxyMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData) +{ + JNIEnv* env = static_cast<JNIEnv*>(aData); + NativeToJavaProxyMap::Entry* entry = + static_cast<NativeToJavaProxyMap::Entry*>(aHeader); + + // first, delete XPCOM instances from the Java proxies + nsresult rv; + NativeToJavaProxyMap::ProxyList* item = entry->list; + while(item != nsnull) { + void* xpcom_obj; + jobject javaObject = env->CallObjectMethod(item->javaObject, getReferentMID); + rv = GetXPCOMInstFromProxy(env, javaObject, &xpcom_obj); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get XPCOM instance from Java proxy"); + + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst = static_cast<JavaXPCOMInstance*>(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + char* iid_str = item->iid.ToString(); + LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + javaObject), + (PRUint32) entry, iid_str)); + PR_Free(iid_str); +#endif + delete inst; // releases native XPCOM object + } + + NativeToJavaProxyMap::ProxyList* next = item->next; + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); + delete item; + item = next; + } + + return PL_DHASH_REMOVE; +} + +nsresult +NativeToJavaProxyMap::Destroy(JNIEnv* env) +{ + // This is only called from FreeGlobals(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + PL_DHashTableEnumerate(mHashTable, DestroyJavaProxyMappingEnum, env); + PL_DHashTableDestroy(mHashTable); + mHashTable = nsnull; + + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Add(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aProxy) +{ + nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast<Entry*>(PL_DHashTableOperate(mHashTable, + aXPCOMObject, + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + jobject ref = nsnull; + jobject weakRefObj = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aProxy); + if (weakRefObj) + ref = env->NewGlobalRef(weakRefObj); + if (!ref) + return NS_ERROR_OUT_OF_MEMORY; + + // Add Java proxy weak reference ref to start of list + ProxyList* item = new ProxyList(ref, aIID, e->list); + e->key = aXPCOMObject; + e->list = item; + +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, aProxy), + (PRUint32) aXPCOMObject, iid_str)); + PR_Free(iid_str); +#endif + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Find(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID, jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + nsAutoLock lock(gJavaXPCOMLock); + + *aResult = nsnull; + Entry* e = static_cast<Entry*>(PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + ProxyList* item = e->list; + while (item != nsnull && *aResult == nsnull) { + if (item->iid.Equals(aIID)) { + jobject referentObj = env->CallObjectMethod(item->javaObject, + getReferentMID); + if (!env->IsSameObject(referentObj, NULL)) { + *aResult = referentObj; +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("< NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + *aResult), + (PRUint32) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + } + } + item = item->next; + } + + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Remove(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID) +{ + // This is only called from finalizeProxy(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast<Entry*>(PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) { + NS_WARNING("XPCOM object not found in hash table"); + return NS_ERROR_FAILURE; + } + + ProxyList* item = e->list; + ProxyList* last = e->list; + while (item != nsnull) { + if (item->iid.Equals(aIID)) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + item->javaObject), + (PRUint32) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); + if (item == e->list) { + e->list = item->next; + if (e->list == nsnull) + PL_DHashTableOperate(mHashTable, aNativeObject, PL_DHASH_REMOVE); + } else { + last->next = item->next; + } + + delete item; + return NS_OK; + } + + last = item; + item = item->next; + } + + NS_WARNING("Java proxy matching given IID not found"); + return NS_ERROR_FAILURE; +} + +nsresult +JavaToXPTCStubMap::Init() +{ + mHashTable = PL_NewDHashTable(PL_DHashGetStubOps(), nsnull, + sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + + +PLDHashOperator +DestroyXPTCMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData) +{ + JavaToXPTCStubMap::Entry* entry = + static_cast<JavaToXPTCStubMap::Entry*>(aHeader); + + // The XPTC stub will be released by the XPCOM side, if it hasn't been + // already. We just need to delete the Java global ref held by the XPTC stub, + // so the Java garbage collector can handle the Java object when necessary. + entry->xptcstub->DeleteStrongRef(); + + return PL_DHASH_REMOVE; +} + +nsresult +JavaToXPTCStubMap::Destroy() +{ + // This is only called from FreeGlobals(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + PL_DHashTableEnumerate(mHashTable, DestroyXPTCMappingEnum, nsnull); + PL_DHashTableDestroy(mHashTable); + mHashTable = nsnull; + + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Add(jint aJavaObjectHashCode, nsJavaXPTCStub* aProxy) +{ + nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast<Entry*> + (PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + NS_ASSERTION(e->key == nsnull, + "XPTCStub for given Java object already exists in hash table"); + e->key = aJavaObjectHashCode; + e->xptcstub = aProxy; + +#ifdef DEBUG_JAVAXPCOM + nsIInterfaceInfo* iface_info; + aProxy->GetInterfaceInfo(&iface_info); + nsIID* iid; + iface_info->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("+ JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) aJavaObjectHashCode, (PRUint32) aProxy, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); + NS_RELEASE(iface_info); +#endif + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Find(jint aJavaObjectHashCode, const nsIID& aIID, + nsJavaXPTCStub** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + nsAutoLock lock(gJavaXPCOMLock); + + *aResult = nsnull; + Entry* e = static_cast<Entry*> + (PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + nsresult rv = e->xptcstub->QueryInterface(aIID, (void**) aResult); + +#ifdef DEBUG_JAVAXPCOM + if (NS_SUCCEEDED(rv)) { + char* iid_str = aIID.ToString(); + LOG(("< JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) aJavaObjectHashCode, (PRUint32) *aResult, iid_str)); + PR_Free(iid_str); + } +#endif + + // NS_NOINTERFACE is not an error condition + if (rv == NS_NOINTERFACE) + rv = NS_OK; + return rv; +} + +nsresult +JavaToXPTCStubMap::Remove(jint aJavaObjectHashCode) +{ + PL_DHashTableOperate(mHashTable, NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_REMOVE); + +#ifdef DEBUG_JAVAXPCOM + LOG(("- JavaToXPTCStubMap (Java=%08x)\n", (PRUint32) aJavaObjectHashCode)); +#endif + + return NS_OK; +} + + +/********************************************************** + * JavaXPCOMInstance + *********************************************************/ +JavaXPCOMInstance::JavaXPCOMInstance(nsISupports* aInstance, + nsIInterfaceInfo* aIInfo) + : mInstance(aInstance) + , mIInfo(aIInfo) +{ + NS_ADDREF(mInstance); + NS_ADDREF(mIInfo); +} + +JavaXPCOMInstance::~JavaXPCOMInstance() +{ + nsresult rv = NS_OK; + +#ifdef VBOX +# if 0 + nsCOMPtr<nsIEventQueue> eq = do_GetMainThreadQueue(); + rv = NS_ProxyRelease(eq.get(), mInstance); + rv |= NS_ProxyRelease(eq.get(), mIInfo); +# else + // The above code crashes in nsTraceRefcntImpl::LogAddCOMPtr() (@bugref 7620) + NS_RELEASE(mInstance); + NS_RELEASE(mIInfo); + rv = NS_OK; +# endif +#else + // Need to release these objects on the main thread. + nsCOMPtr<nsIThread> thread = do_GetMainThread(); + if (thread) { + rv = NS_ProxyRelease(thread, mInstance); + rv |= NS_ProxyRelease(thread, mIInfo); + } +#endif + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); +} + + +/******************************* + * Helper functions + *******************************/ + +nsresult +NativeInterfaceToJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + // If the object is an nsJavaXPTCStub, then get the Java object directly + nsJavaXPTCStub* stub = nsnull; + aXPCOMObject->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub); + if (stub) { + *aResult = stub->GetJavaObject(); + NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object"); + NS_RELEASE(stub); + return NS_OK; + } + + // ... else, get a Java wrapper for the native object + return GetNewOrUsedJavaWrapper(env, aXPCOMObject, aIID, aObjectLoader, + aResult); +} + +nsresult +JavaObjectToNativeInterface(JNIEnv* env, jobject aJavaObject, const nsIID& aIID, + void** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + *aResult = nsnull; + + // If the given Java object is one of our Java proxies, then query the + // associated XPCOM object directly from the proxy. + jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass, + isXPCOMJavaProxyMID, + aJavaObject); + if (env->ExceptionCheck()) + return NS_ERROR_FAILURE; + + if (isProxy) { + void* inst; + rv = GetXPCOMInstFromProxy(env, aJavaObject, &inst); + NS_ENSURE_SUCCESS(rv, rv); + + nsISupports* rootObject = + static_cast<JavaXPCOMInstance*>(inst)->GetInstance(); + rv = rootObject->QueryInterface(aIID, aResult); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + // ... else, we get an nsJavaXPTCStub + return nsJavaXPTCStub::GetNewOrUsed(env, aJavaObject, aIID, aResult); +} + +nsresult +GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const XPTMethodDescriptor *methodInfo, + const nsXPTParamInfo ¶mInfo, PRUint8 paramType, + PRUint16 methodIndex, nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, nsID &result) +{ + nsresult rv; + + switch (paramType) + { + case nsXPTType::T_INTERFACE: + rv = iinfo->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, &result); + break; + + case nsXPTType::T_INTERFACE_IS: + { + PRUint8 argnum; + rv = iinfo->GetInterfaceIsArgNumberForParam(methodIndex, ¶mInfo, + &argnum); + if (NS_FAILED(rv)) + break; + + const nsXPTParamInfo& arg_param = methodInfo->params[argnum]; + const nsXPTType& arg_type = arg_param.GetType(); + + // The xpidl compiler ensures this. We reaffirm it for safety. + if (!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsID *p = nsnull; + if (isFullVariantArray) { + p = (nsID *) ((nsXPTCVariant*) dispatchParams)[argnum].val.p; + } else { + p = (nsID *) dispatchParams[argnum].val.p; + } + if (!p) + return NS_ERROR_UNEXPECTED; + + result = *p; + break; + } + + default: + rv = NS_ERROR_UNEXPECTED; + } + return rv; +} + + +/******************************* + * JNI helper functions + *******************************/ + +JNIEnv* +GetJNIEnv() +{ + JNIEnv* env = nsnull; + jint rc = gCachedJVM->GetEnv((void**) &env, JNI_VERSION_1_2); +#ifdef VBOX + if (env == nsnull) + { + rc = gCachedJVM->AttachCurrentThreadAsDaemon((void**)&env, nsnull); + printf("attaching\n"); + } +#endif + NS_ASSERTION(rc == JNI_OK && env != nsnull, + "Current thread not attached to given JVM instance"); + return env; +} + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage) +{ + // Only throw this exception if one hasn't already been thrown, so we don't + // mask a previous exception/error. + if (env->ExceptionCheck()) + return; + + // If the error code we get is for an Out Of Memory error, try to throw an + // OutOfMemoryError. The JVM may have enough memory to create this error. + if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) { + jclass clazz = env->FindClass("java/lang/OutOfMemoryError"); + if (clazz) { + env->ThrowNew(clazz, aMessage); + } + env->DeleteLocalRef(clazz); + return; + } + + // If the error was not handled above, then create an XPCOMException with the + // given error code and message. + + // Create parameters and method signature. Max of 2 params. The error code + // comes before the message string. + PRInt64 errorCode = aErrorCode ? aErrorCode : NS_ERROR_FAILURE; + nsCAutoString methodSig("(J"); + jstring message = nsnull; + if (aMessage) { + message = env->NewStringUTF(aMessage); + if (!message) { + return; + } + methodSig.AppendLiteral("Ljava/lang/String;"); + } + methodSig.AppendLiteral(")V"); + + // In some instances (such as in shutdownXPCOM() and termEmbedding()), we + // will need to throw an exception when JavaXPCOM has already been + // terminated. In such a case, 'xpcomExceptionClass' will be null. So we + // reset it temporarily in order to throw the appropriate exception. + if (xpcomExceptionClass == nsnull) { + xpcomExceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException"); + if (!xpcomExceptionClass) { + return; + } + } + + // create exception object + jthrowable throwObj = nsnull; + jmethodID mid = env->GetMethodID(xpcomExceptionClass, "<init>", + methodSig.get()); + if (mid) { + throwObj = (jthrowable) env->NewObject(xpcomExceptionClass, mid, errorCode, + message); + } + NS_ASSERTION(throwObj, "Failed to create XPCOMException object"); + + // throw exception + if (throwObj) { + env->Throw(throwObj); + } +} + +nsAString* +jstring_to_nsAString(JNIEnv* env, jstring aString) +{ + const PRUnichar* buf = nsnull; + if (aString) { + buf = env->GetStringChars(aString, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsString* str = new nsString(buf); + + if (aString) { + env->ReleaseStringChars(aString, buf); + } else { + str->SetIsVoid(PR_TRUE); + } + + // returns string, or nsnull if 'new' failed + return str; +} + +nsACString* +jstring_to_nsACString(JNIEnv* env, jstring aString) +{ + const char* buf = nsnull; + if (aString) { + buf = env->GetStringUTFChars(aString, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsCString* str = new nsCString(buf); + + if (aString) { + env->ReleaseStringUTFChars(aString, buf); + } else { + str->SetIsVoid(PR_TRUE); + } + + // returns string, or nsnull if 'new' failed + return str; +} + +nsresult +File_to_nsILocalFile(JNIEnv* env, jobject aFile, nsILocalFile** aLocalFile) +{ + nsresult rv = NS_ERROR_FAILURE; + jstring pathName = nsnull; + jclass clazz = env->FindClass("java/io/File"); + if (clazz) { + jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath", + "()Ljava/lang/String;"); + if (pathMID) { + pathName = (jstring) env->CallObjectMethod(aFile, pathMID); + if (pathName != nsnull && !env->ExceptionCheck()) + rv = NS_OK; + } + } + + if (NS_SUCCEEDED(rv)) { + nsAString* path = jstring_to_nsAString(env, pathName); + if (!path) + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_SUCCEEDED(rv)) { + rv = NS_NewLocalFile(*path, false, aLocalFile); + delete path; + } + } + + return rv; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h new file mode 100644 index 00000000..894a8cb8 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h @@ -0,0 +1,392 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsJavaXPCOMBindingUtils_h_ +#define _nsJavaXPCOMBindingUtils_h_ + +#include "jni.h" +#include "xptcall.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "pldhash.h" +#include "nsJavaXPTCStub.h" +#include "nsAutoLock.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" +#include "nsILocalFile.h" + +//#define DEBUG_JAVAXPCOM +//#define DEBUG_JAVAXPCOM_REFCNT + +#ifdef DEBUG_JAVAXPCOM +#define LOG(x) printf x +#else +#define LOG(x) /* nothing */ +#endif + + +/********************* + * Java JNI globals + *********************/ + +extern jclass systemClass; +extern jclass booleanClass; +extern jclass charClass; +extern jclass byteClass; +extern jclass shortClass; +extern jclass intClass; +extern jclass longClass; +extern jclass floatClass; +extern jclass doubleClass; +extern jclass stringClass; +extern jclass nsISupportsClass; +extern jclass xpcomExceptionClass; +extern jclass xpcomJavaProxyClass; +extern jclass weakReferenceClass; +extern jclass javaXPCOMUtilsClass; + +extern jmethodID hashCodeMID; +extern jmethodID booleanValueMID; +extern jmethodID booleanInitMID; +extern jmethodID charValueMID; +extern jmethodID charInitMID; +extern jmethodID byteValueMID; +extern jmethodID byteInitMID; +extern jmethodID shortValueMID; +extern jmethodID shortInitMID; +extern jmethodID intValueMID; +extern jmethodID intInitMID; +extern jmethodID longValueMID; +extern jmethodID longInitMID; +extern jmethodID floatValueMID; +extern jmethodID floatInitMID; +extern jmethodID doubleValueMID; +extern jmethodID doubleInitMID; +extern jmethodID createProxyMID; +extern jmethodID isXPCOMJavaProxyMID; +extern jmethodID getNativeXPCOMInstMID; +extern jmethodID weakReferenceConstructorMID; +extern jmethodID getReferentMID; +extern jmethodID clearReferentMID; +extern jmethodID findClassInLoaderMID; + +#ifdef DEBUG_JAVAXPCOM +extern jmethodID getNameMID; +extern jmethodID proxyToStringMID; +#endif + +class NativeToJavaProxyMap; +extern NativeToJavaProxyMap* gNativeToJavaProxyMap; +class JavaToXPTCStubMap; +extern JavaToXPTCStubMap* gJavaToXPTCStubMap; + +extern nsTHashtable<nsDepCharHashKey>* gJavaKeywords; + +// The Java garbage collector runs in a separate thread. Since it calls the +// finalizeProxy() function in nsJavaWrapper.cpp, we need to make sure that +// all the structures touched by finalizeProxy() are multithread aware. +extern PRLock* gJavaXPCOMLock; + +extern PRBool gJavaXPCOMInitialized; + +/** + * Initialize global structures used by JavaXPCOM. + * @param env Java environment pointer + * @return PR_TRUE if JavaXPCOM is initialized; PR_FALSE if an error occurred + */ +PRBool InitializeJavaGlobals(JNIEnv *env); + +/** + * Frees global structures that were allocated by InitializeJavaGlobals(). + * @param env Java environment pointer + */ +void FreeJavaGlobals(JNIEnv* env); + + +/************************* + * JavaXPCOMInstance + *************************/ + +class JavaXPCOMInstance +{ +public: + JavaXPCOMInstance(nsISupports* aInstance, nsIInterfaceInfo* aIInfo); + ~JavaXPCOMInstance(); + + nsISupports* GetInstance() { return mInstance; } + nsIInterfaceInfo* InterfaceInfo() { return mIInfo; } + +private: + nsISupports* mInstance; + nsIInterfaceInfo* mIInfo; +}; + + +/************************************** + * Java<->XPCOM object mappings + **************************************/ + +/** + * Maps native XPCOM objects to their associated Java proxy object. + */ +class NativeToJavaProxyMap +{ + friend PLDHashOperator DestroyJavaProxyMappingEnum(PLDHashTable* aTable, + PLDHashEntryHdr* aHeader, + PRUint32 aNumber, + void* aData); + +protected: + struct ProxyList + { + ProxyList(const jobject aRef, const nsIID& aIID, ProxyList* aList) + : javaObject(aRef) + , iid(aIID) + , next(aList) + { } + + const jobject javaObject; + const nsIID iid; + ProxyList* next; + }; + + struct Entry : public PLDHashEntryHdr + { + nsISupports* key; + ProxyList* list; + }; + +public: + NativeToJavaProxyMap() + : mHashTable(nsnull) + { } + + ~NativeToJavaProxyMap() + { + NS_ASSERTION(mHashTable == nsnull, + "MUST call Destroy() before deleting object"); + } + + nsresult Init(); + + nsresult Destroy(JNIEnv* env); + + nsresult Add(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID, + jobject aProxy); + + nsresult Find(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID, + jobject* aResult); + + nsresult Remove(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID); + +protected: + PLDHashTable* mHashTable; +}; + +/** + * Maps Java objects to their associated nsJavaXPTCStub. + */ +class JavaToXPTCStubMap +{ + friend PLDHashOperator DestroyXPTCMappingEnum(PLDHashTable* aTable, + PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData); + +protected: + struct Entry : public PLDHashEntryHdr + { + jint key; + nsJavaXPTCStub* xptcstub; + }; + +public: + JavaToXPTCStubMap() + : mHashTable(nsnull) + { } + + ~JavaToXPTCStubMap() + { + NS_ASSERTION(mHashTable == nsnull, + "MUST call Destroy() before deleting object"); + } + + nsresult Init(); + + nsresult Destroy(); + + nsresult Add(jint aJavaObjectHashCode, nsJavaXPTCStub* aProxy); + + nsresult Find(jint aJavaObjectHashCode, const nsIID& aIID, + nsJavaXPTCStub** aResult); + + nsresult Remove(jint aJavaObjectHashCode); + +protected: + PLDHashTable* mHashTable; +}; + + +/******************************* + * Helper functions + *******************************/ + +/** + * Convert a native nsISupports to a Java object. + * + * @param env Java environment pointer + * @param aXPCOMObject XPCOM object for which to find/create Java object + * @param aIID desired interface IID for Java object + * @param aObjectLoader Java object whose class loader we use for finding + * classes; can be null + * @param aResult on success, holds reference to Java object + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult NativeInterfaceToJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult); + +/** + * Convert a Java object to a native nsISupports object. + * + * @param env Java environment pointer + * @param aJavaObject Java object for which to find/create XPCOM object + * @param aIID desired interface IID for XPCOM object + * @param aResult on success, holds AddRef'd reference to XPCOM object + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult JavaObjectToNativeInterface(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult); + +nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const XPTMethodDescriptor *methodInfo, + const nsXPTParamInfo ¶mInfo, + PRUint8 paramType, PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, + nsID &result); + +/** + * Returns the Class object associated with the class or interface with the + * given string name, using the class loader of the given object. + * + * @param env Java environment pointer + * @param aObjectLoader Java object whose class loader is used to load class + * @param aClassName fully qualified name of class to load + * + * @return java.lang.Class object of requested Class; NULL if the class + * wasn't found + * + * @see http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#classops + */ +inline jclass +FindClassInLoader(JNIEnv* env, jobject aObjectLoader, const char* aClassName) +{ + jclass clazz = nsnull; + jstring name = env->NewStringUTF(aClassName); + if (name) + clazz = (jclass) env->CallStaticObjectMethod(javaXPCOMUtilsClass, + findClassInLoaderMID, aObjectLoader, name); + +#ifdef DEBUG + if (!clazz) + fprintf(stderr, "WARNING: failed to find class [%s]\n", aClassName); +#endif + return clazz; +} + + +/******************************* + * JNI helper functions + *******************************/ + +/** + * Returns a pointer to the appropriate JNIEnv structure. This function is + * useful in callbacks or other functions that are not called directly from + * Java and therefore do not have the JNIEnv structure passed in. + * + * @return pointer to JNIEnv structure for current thread + */ +JNIEnv* GetJNIEnv(); + +/** + * Constructs and throws an exception. Some error codes (such as + * NS_ERROR_OUT_OF_MEMORY) are handled by the appropriate Java exception/error. + * Otherwise, an instance of XPCOMException is created with the given error + * code and message. + * + * @param env Java environment pointer + * @param aErrorCode The error code returned by an XPCOM/Gecko function. Pass + * zero for the default behaviour. + * @param aMessage A string that provides details for throwing this + * exception. Pass in <code>nsnull</code> for the default + * behaviour. + * + * @throws OutOfMemoryError if aErrorCode == NS_ERROR_OUT_OF_MEMORY + * XPCOMException for all other error codes + */ +void ThrowException(JNIEnv* env, const nsresult aErrorCode, + const char* aMessage); + +/** + * Helper functions for converting from java.lang.String to + * nsAString/nsACstring. Caller must delete nsAString/nsACString. + * + * @param env Java environment pointer + * @param aString Java string to convert + * + * @return nsAString/nsACString with same content as given Java string; + * a 'void' nsAString/nsACString object if aString is + * <code>null</code>; or <code>nsnull</code> if out of memory + */ +nsAString* jstring_to_nsAString(JNIEnv* env, jstring aString); +nsACString* jstring_to_nsACString(JNIEnv* env, jstring aString); + +/** + * Helper function for converting from java.io.File to nsILocalFile. + * + * @param env Java environment pointer + * @param aFile Java File to convert + * @param aLocalFile returns the converted nsILocalFile + * + * @return NS_OK for success; other values indicate error in conversion + */ +nsresult File_to_nsILocalFile(JNIEnv* env, jobject aFile, + nsILocalFile** aLocalFile); + +#endif // _nsJavaXPCOMBindingUtils_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp new file mode 100644 index 00000000..b0b6b72c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp @@ -0,0 +1,535 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "jni.h" +#include "nsXPCOMPrivate.h" // for XPCOM_DLL defines. +#include "nsXPCOMGlue.h" +#include <stdlib.h> + + +#ifdef VBOX +#include <string.h> +#include "nsDebug.h" +#endif + +#if defined(XP_WIN) || defined(XP_OS2) +#define JX_EXPORT JNIEXPORT +#else +#define JX_EXPORT JNIEXPORT NS_EXPORT +#endif + + +/*********************** + * JNI Load & Unload + ***********************/ + +extern "C" JX_EXPORT jint JNICALL +JNI_OnLoad(JavaVM* vm, void* reserved) +{ + // Let the JVM know that we are using JDK 1.2 JNI features. + return JNI_VERSION_1_2; +} + +extern "C" JX_EXPORT void JNICALL +JNI_OnUnload(JavaVM* vm, void* reserved) +{ +} + +/******************************** + * JavaXPCOM JNI interfaces + ********************************/ + +#define JXM_NATIVE(func) Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_##func + +enum { + kFunc_Initialize, + kFunc_InitEmbedding, + kFunc_TermEmbedding, + kFunc_LockProfileDirectory, + kFunc_NotifyProfile, + kFunc_InitXPCOM, + kFunc_ShutdownXPCOM, + kFunc_GetComponentManager, + kFunc_GetComponentRegistrar, + kFunc_GetServiceManager, + kFunc_NewLocalFile, + kFunc_CallXPCOMMethod, + kFunc_FinalizeProxy, + kFunc_IsSameXPCOMObject, + kFunc_ReleaseProfileLock, + kFunc_GetNativeHandleFromAWT, + kFunc_WrapJavaObject, + kFunc_WrapXPCOMObject +}; + +#define JX_NUM_FUNCS 18 + + +// Get path string from java.io.File object. +jstring +GetJavaFilePath(JNIEnv* env, jobject aFile) +{ + jclass clazz = env->FindClass("java/io/File"); + if (clazz) { + jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath", + "()Ljava/lang/String;"); + if (pathMID) { + return (jstring) env->CallObjectMethod(aFile, pathMID); + } + } + + return nsnull; +} +#ifdef VBOX + +#include "nsXPTCUtils.h" +#include "nsCOMPtr.h" +#include "nsIInterfaceInfoManager.h" +#include "nsJavaInterfaces.h" + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage); + +class nsXPTCJStub : public nsXPTCStubBase +{ + nsCOMPtr<nsIInterfaceInfo> mII; + nsIXPTCProxy* mOuter; + public: + NS_DECL_ISUPPORTS_INHERITED + + nsXPTCJStub(REFNSIID aIID, nsIXPTCProxy* aOuter, nsIInterfaceInfo* ii) + { + mOuter = aOuter; + mII = ii; + } + + virtual ~nsXPTCJStub() + { + } + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) + { + *info = mII; + (*info)->AddRef(); + return NS_OK; + } + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) + { + return mOuter->CallMethod(methodIndex, info, params); + } +}; + +NS_IMETHODIMP_(nsrefcnt) +nsXPTCJStub::AddRef() +{ + return mOuter->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsXPTCJStub::Release() +{ + return mOuter->Release(); +} + +NS_IMETHODIMP nsXPTCJStub::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + nsIID* mIID; + mII->GetInterfaceIID(&mIID); + + if (mIID->Equals(aIID)) { + NS_ADDREF_THIS(); + *aInstancePtr = static_cast<nsISupports*>(this); + return NS_OK; + } + + return mOuter->QueryInterface(aIID, aInstancePtr); +} + +nsresult +NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, + nsISomeInterface* *aResult) +{ + NS_ENSURE_ARG(aOuter && aResult); +#if 0 + xptiInterfaceInfoManager *iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED); + + xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID); + if (!iie || !iie->EnsureResolved()) + return NS_ERROR_FAILURE; + + nsXPTCStubBase* newbase = new nsXPTCStubBase(aOuter, iie); + if (!newbase) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = newbase; +#else + nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr<nsIInterfaceInfo> ii; + nsresult rv; + + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(ii)); + if (NS_FAILED(rv)) + return rv; + + nsXPTCStubBase* newbase = new nsXPTCJStub(aIID, aOuter, ii); + if (!newbase) + return NS_ERROR_OUT_OF_MEMORY; + *aResult = newbase; +#endif + return NS_OK; +} + +void +NS_DestroyXPTCallStub(nsISomeInterface* aStub) +{ + nsXPTCStubBase* stub = static_cast<nsXPTCStubBase*>(aStub); + delete(stub); +} + + +extern "C" void JAVAPROXY_NATIVE(finalizeProxy)(JNIEnv *env, jclass that, jobject aJavaProxy); + +nsresult +FindVBoxMethods(JNIEnv* env, jobject aXPCOMPath, void** aFunctions) +{ + nsresult rv = 0; + + // We only need to care about this function because the C function we offer + // is different from what the Java side expects + aFunctions[kFunc_FinalizeProxy] = (void*)JAVAPROXY_NATIVE(finalizeProxy); + + return rv; +} +#else +// Calls XPCOMGlueStartup using the given java.io.File object, and loads +// the JavaXPCOM methods from the XUL shared library. +nsresult +LoadXULMethods(JNIEnv* env, jobject aXPCOMPath, void** aFunctions) +{ + jstring pathString = GetJavaFilePath(env, aXPCOMPath); + if (!pathString) + return NS_ERROR_FAILURE; + const char* path = env->GetStringUTFChars(pathString, nsnull); + if (!path) + return NS_ERROR_OUT_OF_MEMORY; + + int len = strlen(path); + char* xpcomPath = (char*) malloc(len + sizeof(XPCOM_DLL) + + sizeof(XPCOM_FILE_PATH_SEPARATOR) + 1); + if (!xpcomPath) + return NS_ERROR_OUT_OF_MEMORY; + sprintf(xpcomPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, path); + + nsresult rv = XPCOMGlueStartup(xpcomPath); + free(xpcomPath); + if (NS_FAILED(rv)) + return rv; + +#ifdef XP_WIN32 + // The JNICALL calling convention defines to "__stdcall" on Win32, which + // mangles the name. + nsDynamicFunctionLoad funcs[] = { + { "_Java_org_mozilla_xpcom_internal_MozillaImpl_initialize@8", + (NSFuncPtr*) &aFunctions[kFunc_Initialize] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding@20", + (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding@8", + (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory@12", + (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile@8", + (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM@16", + (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM@12", + (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager@8", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar@8", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager@8", + (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile@16", + (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod@20", + (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy@12", + (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject@16", + (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] }, + { "_Java_org_mozilla_xpcom_ProfileLock_release@16", + (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] }, + { "_Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT@12", + (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] }, + { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject@16", + (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] }, + { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject@20", + (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] }, + { nsnull, nsnull } + }; +#else + nsDynamicFunctionLoad funcs[] = { + { "Java_org_mozilla_xpcom_internal_MozillaImpl_initialize", + (NSFuncPtr*) &aFunctions[kFunc_Initialize] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding", + (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding", + (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory", + (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile", + (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM", + (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM", + (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager", + (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile", + (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod", + (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy", + (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject", + (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] }, + { "Java_org_mozilla_xpcom_ProfileLock_release", + (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] }, + { "Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT", + (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] }, + { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject", + (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] }, + { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject", + (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] }, + { nsnull, nsnull } + }; +#endif + + rv = XPCOMGlueLoadXULFunctions(funcs); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage) +{ + // Only throw this exception if one hasn't already been thrown, so we don't + // mask a previous exception/error. + if (env->ExceptionCheck()) + return; + + // If the error code we get is for an Out Of Memory error, try to throw an + // OutOfMemoryError. The JVM may have enough memory to create this error. + if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) { + jclass clazz = env->FindClass("java/lang/OutOfMemoryError"); + if (clazz) { + env->ThrowNew(clazz, aMessage); + } + env->DeleteLocalRef(clazz); + return; + } + + // If the error was not handled above, then create an XPCOMException with the + // given error code. + jthrowable throwObj = nsnull; + jclass exceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException"); + if (exceptionClass) { + jmethodID mid = env->GetMethodID(exceptionClass, "<init>", + "(JLjava/lang/String;)V"); + if (mid) { + throwObj = (jthrowable) env->NewObject(exceptionClass, mid, + (PRInt64) aErrorCode, + env->NewStringUTF(aMessage)); + } + } + NS_ASSERTION(throwObj, "Failed to create XPCOMException object"); + + // throw exception + if (throwObj) { + env->Throw(throwObj); + } +} +#endif // VBOX + +// Register the JavaXPCOM native methods. This associates a native Java +// method with its C implementation. +nsresult +RegisterNativeMethods(JNIEnv* env, void** aFunctions) +{ + JNINativeMethod mozilla_methods[] = { + { "initializeNative", "()V", + (void*) aFunctions[kFunc_Initialize] }, + { "getNativeHandleFromAWT", "(Ljava/lang/Object;)J", + (void*) aFunctions[kFunc_GetNativeHandleFromAWT] } + }; + + JNINativeMethod gre_methods[] = { + { "initEmbeddingNative", + "(Ljava/io/File;Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)V", + (void*) aFunctions[kFunc_InitEmbedding] }, + { "termEmbedding", "()V", + (void*) aFunctions[kFunc_TermEmbedding] }, + { "lockProfileDirectory", "(Ljava/io/File;)Lorg/mozilla/xpcom/ProfileLock;", + (void*) aFunctions[kFunc_LockProfileDirectory] }, + { "notifyProfile", "()V", + (void*) aFunctions[kFunc_NotifyProfile] }, + }; + + JNINativeMethod xpcom_methods[] = { + { "initXPCOMNative", + "(Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)Lorg/mozilla/interfaces/nsIServiceManager;", + (void*) aFunctions[kFunc_InitXPCOM] }, + { "shutdownXPCOM", "(Lorg/mozilla/interfaces/nsIServiceManager;)V", + (void*) aFunctions[kFunc_ShutdownXPCOM] }, + { "getComponentManager", "()Lorg/mozilla/interfaces/nsIComponentManager;", + (void*) aFunctions[kFunc_GetComponentManager] }, + { "getComponentRegistrar", "()Lorg/mozilla/interfaces/nsIComponentRegistrar;", + (void*) aFunctions[kFunc_GetComponentRegistrar] }, + { "getServiceManager", "()Lorg/mozilla/interfaces/nsIServiceManager;", + (void*) aFunctions[kFunc_GetServiceManager] }, + { "newLocalFile", "(Ljava/lang/String;Z)Lorg/mozilla/interfaces/nsILocalFile;", + (void*) aFunctions[kFunc_NewLocalFile] } + }; + + JNINativeMethod proxy_methods[] = { + { "callXPCOMMethod", + "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", + (void*) aFunctions[kFunc_CallXPCOMMethod] }, + { "finalizeProxyNative", "(Ljava/lang/Object;)V", + (void*) aFunctions[kFunc_FinalizeProxy] }, + { "isSameXPCOMObject", "(Ljava/lang/Object;Ljava/lang/Object;)Z", + (void*) aFunctions[kFunc_IsSameXPCOMObject] } + }; + + JNINativeMethod lockProxy_methods[] = { + { "releaseNative", "(J)V", + (void*) aFunctions[kFunc_ReleaseProfileLock] } + }; + + JNINativeMethod util_methods[] = { + { "wrapJavaObject", "(Ljava/lang/Object;Ljava/lang/String;)J", + (void*) aFunctions[kFunc_WrapJavaObject] }, + { "wrapXPCOMObject", "(JLjava/lang/String;)Ljava/lang/Object;", + (void*) aFunctions[kFunc_WrapXPCOMObject] } + }; + + jint rc = -1; + jclass clazz = env->FindClass("org/mozilla/xpcom/internal/MozillaImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, mozilla_methods, + sizeof(mozilla_methods) / sizeof(mozilla_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/GREImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, gre_methods, + sizeof(gre_methods) / sizeof(gre_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, xpcom_methods, + sizeof(xpcom_methods) / sizeof(xpcom_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMJavaProxy"); + if (clazz) { + rc = env->RegisterNatives(clazz, proxy_methods, + sizeof(proxy_methods) / sizeof(proxy_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/ProfileLock"); + if (clazz) { + rc = env->RegisterNatives(clazz, lockProxy_methods, + sizeof(lockProxy_methods) / sizeof(lockProxy_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/JavaXPCOMMethods"); + if (clazz) { + rc = env->RegisterNatives(clazz, util_methods, + sizeof(util_methods) / sizeof(util_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + return NS_OK; +} + +// Load the JavaXPCOM methods from the XUL shared library, and registers them +// as Java native methods. +extern "C" JX_EXPORT void JNICALL +JXM_NATIVE(registerJavaXPCOMMethodsNative) (JNIEnv *env, jclass that, + jobject aXPCOMPath) +{ + void* functions[JX_NUM_FUNCS]; + memset(functions, 0, JX_NUM_FUNCS * sizeof(void*)); + +#ifdef VBOX + nsresult rv = FindVBoxMethods(env, aXPCOMPath, functions); + if (NS_SUCCEEDED(rv)) { + rv = RegisterNativeMethods(env, functions); + } +#else + nsresult rv = LoadXULMethods(env, aXPCOMPath, functions); + if (NS_SUCCEEDED(rv)) { + rv = RegisterNativeMethods(env, functions); + } +#endif + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to register JavaXPCOM methods"); + } +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp new file mode 100644 index 00000000..c8136ec4 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp @@ -0,0 +1,1711 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsJavaXPTCStub.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "prmem.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsServiceManagerUtils.h" + + +nsJavaXPTCStub::nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo, + nsresult *rv) + : mJavaStrongRef(nsnull) + , mIInfo(aIInfo) + , mMaster(nsnull) + , mWeakRefCnt(0) +{ + const nsIID *iid = nsnull; + aIInfo->GetIIDShared(&iid); + NS_ASSERTION(iid, "GetIIDShared must not fail!"); + + *rv = InitStub(*iid); + if (NS_FAILED(*rv)) + return; + + JNIEnv* env = GetJNIEnv(); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mJavaWeakRef = env->NewGlobalRef(weakref); + mJavaRefHashCode = env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaObject); + +#ifdef DEBUG_JAVAXPCOM + char* iid_str = iid->ToString(); + LOG(("+ nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); +#endif +} + +nsJavaXPTCStub::~nsJavaXPTCStub() +{ +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::AddRefInternal() +{ + // If this is the first AddRef call, we create a strong global ref to the + // Java object to keep it from being garbage collected. + if (mRefCnt == 0) { + JNIEnv* env = GetJNIEnv(); + jobject referent = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + if (!env->IsSameObject(referent, NULL)) { + mJavaStrongRef = env->NewGlobalRef(referent); + } + NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref"); + } + + // if this is the master interface + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsJavaXPTCStub", sizeof(*this)); + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::AddRef() +{ +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) + 1; + LOG(("= nsJavaXPTCStub::AddRef (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->AddRefInternal(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::ReleaseInternal() +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsJavaXPTCStub"); + if (mRefCnt == 0) { + // delete strong ref; allows Java object to be garbage collected + DeleteStrongRef(); + + // If we have a weak ref, we don't delete this object. + if (mWeakRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + Destroy(); + delete this; + } + return 0; + } + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::Release() +{ +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) - 1; + LOG(("= nsJavaXPTCStub::Release (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->ReleaseInternal(); +} + +void +nsJavaXPTCStub::Destroy() +{ + JNIEnv* env = GetJNIEnv(); + +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("- nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + if (!mMaster) { + // delete each child stub + for (PRInt32 i = 0; i < mChildren.Count(); i++) { + delete (nsJavaXPTCStub*) mChildren[i]; + } + + // Since we are destroying this stub, also remove the mapping. + // It is possible for mJavaStrongRef to be NULL here. That is why we + // store the hash code value earlier. + if (gJavaXPCOMInitialized) { + gJavaToXPTCStubMap->Remove(mJavaRefHashCode); + } + } + + env->CallVoidMethod(mJavaWeakRef, clearReferentMID); + env->DeleteGlobalRef(mJavaWeakRef); +} + +void +nsJavaXPTCStub::ReleaseWeakRef() +{ + // if this is a child + if (mMaster) + mMaster->ReleaseWeakRef(); + + --mWeakRefCnt; + + // If there are no more associated weak refs, and no one else holds a strong + // ref to this object, then delete it. + if (mWeakRefCnt == 0 && mRefCnt == 0) { + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + mRefCnt = 1; /* stabilize */ + Destroy(); + delete this; + } +} + +void +nsJavaXPTCStub::DeleteStrongRef() +{ + if (mJavaStrongRef == nsnull) + return; + + GetJNIEnv()->DeleteGlobalRef(mJavaStrongRef); + mJavaStrongRef = nsnull; +} + +NS_IMETHODIMP +nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) +{ + nsresult rv; + + LOG(("JavaStub::QueryInterface()\n")); + *aInstancePtr = nsnull; + nsJavaXPTCStub *master = mMaster ? mMaster : this; + + // This helps us differentiate between the help classes. + if (aIID.Equals(NS_GET_IID(nsJavaXPTCStub))) + { + *aInstancePtr = master; + NS_ADDREF(this); + return NS_OK; + } + + // always return the master stub for nsISupports + if (aIID.Equals(NS_GET_IID(nsISupports))) + { + *aInstancePtr = master->mXPTCStub; + NS_ADDREF(master); + return NS_OK; + } + + // All Java objects support weak references + if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) + { + *aInstancePtr = static_cast<nsISupportsWeakReference*>(master); + NS_ADDREF(master); + return NS_OK; + } + + // does any existing stub support the requested IID? + nsJavaXPTCStub *stub = master->FindStubSupportingIID(aIID); + if (stub) + { + *aInstancePtr = stub->mXPTCStub; + NS_ADDREF(stub); + return NS_OK; + } + + JNIEnv* env = GetJNIEnv(); + + // Query Java object + LOG(("\tCalling Java object queryInterface\n")); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + + jmethodID qiMID = 0; + jclass clazz = env->GetObjectClass(javaObject); + if (clazz) { + char* sig = "(Ljava/lang/String;)Lorg/mozilla/interfaces/nsISupports;"; + qiMID = env->GetMethodID(clazz, "queryInterface", sig); + NS_ASSERTION(qiMID, "Failed to get queryInterface method ID"); + } + + if (qiMID == 0) { + env->ExceptionClear(); + return NS_NOINTERFACE; + } + + // construct IID string + jstring iid_jstr = nsnull; + char* iid_str = aIID.ToString(); + if (iid_str) { + iid_jstr = env->NewStringUTF(iid_str); + } + if (!iid_str || !iid_jstr) { + env->ExceptionClear(); + return NS_ERROR_OUT_OF_MEMORY; + } + PR_Free(iid_str); + + // call queryInterface method + jobject obj = env->CallObjectMethod(javaObject, qiMID, iid_jstr); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + return NS_ERROR_FAILURE; + } + if (!obj) + return NS_NOINTERFACE; + + // Get interface info for new java object + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIInterfaceInfo> iinfo; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + stub = new nsJavaXPTCStub(obj, iinfo, &rv); + if (!stub) + return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + // add stub to the master's list of children, so we can preserve + // symmetry in future QI calls. the master will delete each child + // when it is destroyed. the refcount of each child is bound to + // the refcount of the master. this is done to deal with code + // like this: + // + // nsCOMPtr<nsIBar> bar = ...; + // nsIFoo *foo; + // { + // nsCOMPtr<nsIFoo> temp = do_QueryInterface(bar); + // foo = temp; + // } + // foo->DoStuff(); + // + // while this code is not valid XPCOM (since it is using |foo| + // after having called Release on it), such code is unfortunately + // very common in the mozilla codebase. the assumption this code + // is making is that so long as |bar| is alive, it should be valid + // to access |foo| even if the code doesn't own a strong reference + // to |foo|! clearly wrong, but we need to support it anyways. + + stub->mMaster = master; + master->mChildren.AppendElement(stub); + + *aInstancePtr = stub->mXPTCStub; + NS_ADDREF(stub); + return NS_OK; +} + +PRBool +nsJavaXPTCStub::SupportsIID(const nsID &iid) +{ + PRBool match; + nsCOMPtr<nsIInterfaceInfo> iter = mIInfo; + do + { + if (NS_SUCCEEDED(iter->IsIID(&iid, &match)) && match) + return PR_TRUE; + + nsCOMPtr<nsIInterfaceInfo> parent; + iter->GetParent(getter_AddRefs(parent)); + iter = parent; + } + while (iter != nsnull); + + return PR_FALSE; +} + +nsJavaXPTCStub * +nsJavaXPTCStub::FindStubSupportingIID(const nsID &iid) +{ + NS_ASSERTION(mMaster == nsnull, "this is not a master stub"); + + if (SupportsIID(iid)) + return this; + + for (PRInt32 i = 0; i < mChildren.Count(); i++) + { + nsJavaXPTCStub *child = (nsJavaXPTCStub *) mChildren[i]; + if (child->SupportsIID(iid)) + return child; + } + return nsnull; +} + +NS_IMETHODIMP +nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aMethodInfo, + nsXPTCMiniVariant *aParams) +{ +#ifdef DEBUG_JAVAXPCOM + const char* ifaceName; + mIInfo->GetNameShared(&ifaceName); + LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); +#endif + + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + + nsCAutoString methodSig("("); + + // Create jvalue array to hold Java params + PRUint8 paramCount = aMethodInfo->num_args; + jvalue* java_params = nsnull; + const nsXPTParamInfo* retvalInfo = nsnull; + if (paramCount) { + java_params = new jvalue[paramCount]; + if (!java_params) + return NS_ERROR_OUT_OF_MEMORY; + + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; + if (!paramInfo.IsRetval()) { + rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i], methodSig); + } else { + retvalInfo = ¶mInfo; + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed"); + } + + // Finish method signature + if (NS_SUCCEEDED(rv)) { + methodSig.Append(')'); + if (retvalInfo) { + nsCAutoString retvalSig; + rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams, + retvalSig); + methodSig.Append(retvalSig); + } else { + methodSig.Append('V'); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed"); + } + + // Get Java method to call + jmethodID mid = nsnull; + if (NS_SUCCEEDED(rv)) { + nsCAutoString methodName; + if (XPT_MD_IS_GETTER(aMethodInfo->flags) || + XPT_MD_IS_SETTER(aMethodInfo->flags)) { + if (XPT_MD_IS_GETTER(aMethodInfo->flags)) + methodName.AppendLiteral("get"); + else + methodName.AppendLiteral("set"); + methodName.AppendASCII(aMethodInfo->name); + methodName.SetCharAt(toupper(methodName[3]), 3); + } else { + methodName.AppendASCII(aMethodInfo->name); + methodName.SetCharAt(tolower(methodName[0]), 0); + } + // If it's a Java keyword, then prepend an underscore + if (gJavaKeywords->GetEntry(methodName.get())) { + methodName.Insert('_', 0); + } + + jclass clazz = env->GetObjectClass(javaObject); + if (clazz) + mid = env->GetMethodID(clazz, methodName.get(), methodSig.get()); + NS_ASSERTION(mid, "Failed to get requested method for Java object"); + if (!mid) + rv = NS_ERROR_FAILURE; + } + + // Call method + jvalue retval; + if (NS_SUCCEEDED(rv)) { + if (!retvalInfo) { + env->CallVoidMethodA(javaObject, mid, java_params); + } else { + switch (retvalInfo->GetType().TagPart()) + { + case nsXPTType::T_I8: + retval.b = env->CallByteMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + retval.s = env->CallShortMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + retval.i = env->CallIntMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + retval.j = env->CallLongMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_FLOAT: + retval.f = env->CallFloatMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + retval.d = env->CallDoubleMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_BOOL: + retval.z = env->CallBooleanMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + retval.c = env->CallCharMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + retval.l = env->CallObjectMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_VOID: + retval.j = env->CallLongMethodA(javaObject, mid, java_params); + break; + + default: + NS_WARNING("Unhandled retval type"); + break; + } + } + + // Check for exception from called Java function + jthrowable exp = env->ExceptionOccurred(); + if (exp) { + // If the exception is an instance of XPCOMException, then get the + // nsresult from the exception instance. Else, default to + // NS_ERROR_FAILURE. + if (env->IsInstanceOf(exp, xpcomExceptionClass)) { + jfieldID fid; + fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J"); + if (fid) { + rv = env->GetLongField(exp, fid); + } else { + rv = NS_ERROR_FAILURE; + } + NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException"); + } else { + rv = NS_ERROR_FAILURE; + } + } + } + + // Handle any 'inout', 'out' and 'retval' params + if (NS_SUCCEEDED(rv)) { + for (PRUint8 i = 0; i < paramCount; i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; + if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in' + continue; + + // If param is null, then caller is not expecting an output value. + if (aParams[i].val.p == nsnull) + continue; + + if (!paramInfo.IsRetval()) { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i]); + } else { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], retval); + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed"); + } + + if (java_params) + delete [] java_params; + +#ifdef DEBUG + if (env->ExceptionCheck()) + env->ExceptionDescribe(); +#endif + env->ExceptionClear(); + + LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); + return rv; +} + +/** + * Handle 'in', 'inout', and 'out' params + */ +nsresult +nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue, + nsACString &aMethodSig) +{ + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + const nsXPTType &type = aParamInfo.GetType(); + + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.b = aVariant.val.i8; + aMethodSig.Append('B'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jbyteArray array = env->NewByteArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetByteArrayRegion(array, 0, 1, (jbyte*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[B"); + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.s = (tag == nsXPTType::T_I16) ? aVariant.val.i16 : + aVariant.val.u8; + aMethodSig.Append('S'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jshortArray array = env->NewShortArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetShortArrayRegion(array, 0, 1, (jshort*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[S"); + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.i = (tag == nsXPTType::T_I32) ? aVariant.val.i32 : + aVariant.val.u16; + aMethodSig.Append('I'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jintArray array = env->NewIntArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetIntArrayRegion(array, 0, 1, (jint*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[I"); + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.j = (tag == nsXPTType::T_I64) ? aVariant.val.i64 : + aVariant.val.u32; + aMethodSig.Append('J'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jlongArray array = env->NewLongArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[J"); + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.f = aVariant.val.f; + aMethodSig.Append('F'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jfloatArray array = env->NewFloatArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetFloatArrayRegion(array, 0, 1, (jfloat*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[F"); + } + } + break; + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.d = (tag == nsXPTType::T_DOUBLE) ? aVariant.val.d : + aVariant.val.u64; + aMethodSig.Append('D'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jdoubleArray array = env->NewDoubleArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetDoubleArrayRegion(array, 0, 1, (jdouble*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[D"); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.z = aVariant.val.b; + aMethodSig.Append('Z'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jbooleanArray array = env->NewBooleanArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetBooleanArrayRegion(array, 0, 1, (jboolean*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Z"); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (!aParamInfo.IsOut()) { // 'in' + if (tag == nsXPTType::T_CHAR) + aJValue.c = aVariant.val.c; + else + aJValue.c = aVariant.val.wc; + aMethodSig.Append('C'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jcharArray array = env->NewCharArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetCharArrayRegion(array, 0, 1, (jchar*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[C"); + } + } + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + void* ptr = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + ptr = aVariant.val.p; + } else if (aVariant.val.p) { // 'inout' & 'out' + void** variant = static_cast<void**>(aVariant.val.p); + ptr = *variant; + } + + jobject str; + if (ptr) { + if (tag == nsXPTType::T_CHAR_STR) { + str = env->NewStringUTF((const char*) ptr); + } else { + const PRUnichar* buf = (const PRUnichar*) ptr; + str = env->NewString(buf, nsCRT::strlen(buf)); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + str = nsnull; + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = str; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, stringClass, str); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_IID: + { + nsID* iid = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + iid = static_cast<nsID*>(aVariant.val.p); + } else if (aVariant.val.p) { // 'inout' & 'out' + nsID** variant = static_cast<nsID**>(aVariant.val.p); + iid = *variant; + } + + jobject str = nsnull; + if (iid) { + char iid_str[NSID_LENGTH]; + iid->ToProvidedString(iid_str); + str = env->NewStringUTF(iid_str); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = str; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, stringClass, str); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsISupports* xpcom_obj = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + xpcom_obj = static_cast<nsISupports*>(aVariant.val.p); + } else if (aVariant.val.p) { // 'inout' & 'out' + nsISupports** variant = static_cast<nsISupports**>(aVariant.val.p); + xpcom_obj = *variant; + } + + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aParamInfo.GetType().TagPart(), aMethodIndex, + aDispatchParams, PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // get name of interface + char* iface_name = nsnull; + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + break; + + rv = iim->GetNameForIID(&iid, &iface_name); + if (NS_FAILED(rv) || !iface_name) + break; + + jobject java_stub = nsnull; + if (xpcom_obj) { + // Get matching Java object for given xpcom object + jobject objLoader = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + rv = NativeInterfaceToJavaObject(env, xpcom_obj, iid, objLoader, + &java_stub); + if (NS_FAILED(rv)) + break; + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = java_stub; + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, nsISupportsClass, java_stub); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.Append('['); + } + + if (tag != nsXPTType::T_INTERFACE_IS) { + aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/"); + aMethodSig.AppendASCII(iface_name); + aMethodSig.Append(';'); + } else { + aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;"); + } + + nsMemory::Free(iface_name); + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + // This only handle 'in' or 'in dipper' params. In XPIDL, the 'out' + // descriptor is mapped to 'in dipper'. + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsString* str = static_cast<nsString*>(aVariant.val.p); + if (!str) { + rv = NS_ERROR_FAILURE; + break; + } + + jstring jstr = nsnull; + if (!str->IsVoid()) { + jstr = env->NewString(str->get(), str->Length()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + aJValue.l = jstr; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + // This only handle 'in' or 'in dipper' params. In XPIDL, the 'out' + // descriptor is mapped to 'in dipper'. + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsCString* str = static_cast<nsCString*>(aVariant.val.p); + if (!str) { + rv = NS_ERROR_FAILURE; + break; + } + + jstring jstr = nsnull; + if (!str->IsVoid()) { + jstr = env->NewStringUTF(str->get()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + aJValue.l = jstr; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } + break; + + // Pass the 'void*' address as a long + case nsXPTType::T_VOID: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.j = reinterpret_cast<jlong>(aVariant.val.p); + aMethodSig.Append('J'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jlongArray array = env->NewLongArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[J"); + } + } + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +nsresult +nsJavaXPTCStub::GetRetvalSig(const nsXPTParamInfo* aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsACString &aRetvalSig) +{ + PRUint8 type = aParamInfo->GetType().TagPart(); + switch (type) + { + case nsXPTType::T_I8: + aRetvalSig.Append('B'); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + aRetvalSig.Append('S'); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + aRetvalSig.Append('I'); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + aRetvalSig.Append('J'); + break; + + case nsXPTType::T_FLOAT: + aRetvalSig.Append('F'); + break; + + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + aRetvalSig.Append('D'); + break; + + case nsXPTType::T_BOOL: + aRetvalSig.Append('Z'); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + aRetvalSig.Append('C'); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + aRetvalSig.AppendLiteral("Ljava/lang/String;"); + break; + + case nsXPTType::T_INTERFACE: + { + nsID iid; + nsresult rv = GetIIDForMethodParam(mIInfo, aMethodInfo, *aParamInfo, type, + aMethodIndex, aDispatchParams, + PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // get name of interface + char* iface_name = nsnull; + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + break; + + rv = iim->GetNameForIID(&iid, &iface_name); + if (NS_FAILED(rv) || !iface_name) + break; + + aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/"); + aRetvalSig.AppendASCII(iface_name); + aRetvalSig.Append(';'); + nsMemory::Free(iface_name); + break; + } + + case nsXPTType::T_INTERFACE_IS: + aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;"); + break; + + case nsXPTType::T_VOID: + aRetvalSig.Append('J'); + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +/** + * Handle 'inout', 'out', and 'retval' params + */ +nsresult +nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor *aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue) +{ + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + const nsXPTType &type = aParamInfo.GetType(); + + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + { + jbyte value; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.b; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetByteArrayRegion((jbyteArray) aJValue.l, 0, 1, &value); + } + if (aVariant.val.p) + *((PRInt8 *) aVariant.val.p) = value; + } + break; + + case nsXPTType::T_U8: + case nsXPTType::T_I16: + { + jshort value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.s; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetShortArrayRegion((jshortArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U8) + *((PRUint8 *) aVariant.val.p) = value; + else + *((PRInt16 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_U16: + case nsXPTType::T_I32: + { + jint value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.i; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetIntArrayRegion((jintArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U16) + *((PRUint16 *) aVariant.val.p) = value; + else + *((PRInt32 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_U32: + case nsXPTType::T_I64: + { + jlong value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.j; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U32) + *((PRUint32 *) aVariant.val.p) = value; + else + *((PRInt64 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (aParamInfo.IsRetval()) { // 'retval' + *((float *) aVariant.val.p) = aJValue.f; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetFloatArrayRegion((jfloatArray) aJValue.l, 0, 1, + (jfloat*) aVariant.val.p); + } + } + break; + + // XXX how do we handle 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + jdouble value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.d; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetDoubleArrayRegion((jdoubleArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_DOUBLE) + *((double *) aVariant.val.p) = value; + else + *((PRUint64 *) aVariant.val.p) = static_cast<PRUint64>(value); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (aParamInfo.IsRetval()) { // 'retval' + *((PRBool *) aVariant.val.p) = aJValue.z; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetBooleanArrayRegion((jbooleanArray) aJValue.l, 0, 1, + (jboolean*) aVariant.val.p); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (aParamInfo.IsRetval()) { // 'retval' + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = aJValue.c; + else + *((PRUnichar *) aVariant.val.p) = aJValue.c; + } else if (aJValue.l) { // 'inout' & 'out' + jchar* array = env->GetCharArrayElements((jcharArray) aJValue.l, + nsnull); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = array[0]; + else + *((PRUnichar *) aVariant.val.p) = array[0]; + + env->ReleaseCharArrayElements((jcharArray) aJValue.l, array, JNI_ABORT); + } + } + break; + + case nsXPTType::T_CHAR_STR: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + char** variant = static_cast<char**>(aVariant.val.p); + if (str) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(str, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // If new string is different from one passed in, free old string + // and replace with new string. + if (aParamInfo.IsRetval() || + *variant == nsnull || strcmp(*variant, char_ptr) != 0) + { + if (!aParamInfo.IsRetval() && *variant) + PR_Free(*variant); + + *variant = strdup(char_ptr); + if (*variant == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringUTFChars(str, char_ptr); + } else { + // If we were passed in a string, delete it now, and set to null. + // (Only for 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + PR_Free(*variant); + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + PRUnichar** variant = static_cast<PRUnichar**>(aVariant.val.p); + if (str) { + // Get string buffer + const jchar* wchar_ptr = env->GetStringChars(str, nsnull); + if (!wchar_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // If new string is different from one passed in, free old string + // and replace with new string. We + if (aParamInfo.IsRetval() || + *variant == nsnull || nsCRT::strcmp(*variant, wchar_ptr) != 0) + { + if (!aParamInfo.IsRetval() && *variant) + PR_Free(*variant); + + PRUint32 length = nsCRT::strlen(wchar_ptr); + *variant = (PRUnichar*) PR_Malloc((length + 1) * sizeof(PRUnichar)); + if (*variant) { + memcpy(*variant, wchar_ptr, length * sizeof(PRUnichar)); + (*variant)[length] = 0; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringChars(str, wchar_ptr); + } else { + // If we were passed in a string, delete it now, and set to null. + // (Only for 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + PR_Free(*variant); + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_IID: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + nsID** variant = static_cast<nsID**>(aVariant.val.p); + if (str) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(str, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (!aParamInfo.IsRetval() && *variant) { + // If we were given an nsID, set it to the new string + nsID* oldIID = *variant; + oldIID->Parse(char_ptr); + } else { + // If the argument that was passed in was null, then we need to + // create a new nsID. + nsID* newIID = new nsID; + if (newIID) { + newIID->Parse(char_ptr); + *variant = newIID; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringUTFChars(str, char_ptr); + } else { + // If we were passed in an nsID, delete it now, and set to null. + // (Free only 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + delete *variant; + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + jobject java_obj = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + java_obj = aJValue.l; + } else if (aJValue.l) { // 'inout' & 'out' + java_obj = env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + void* xpcom_obj = nsnull; + if (java_obj) { + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aParamInfo.GetType().TagPart(), aMethodIndex, + aDispatchParams, PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + if (iid.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); + } else { + isWeakRef = PR_FALSE; + } + + rv = JavaObjectToNativeInterface(env, java_obj, iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + rv = ((nsISupports*) xpcom_obj)->QueryInterface(iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. + if (isWeakRef) { + nsISupports* isupports = (nsISupports*) xpcom_obj; + nsCOMPtr<nsISupportsWeakReference> supportsweak = + do_QueryInterface(isupports); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + NS_RELEASE(isupports); + xpcom_obj = weakref; + NS_ADDREF((nsISupports*) xpcom_obj); + } else { + xpcom_obj = nsnull; + } + } + } + + // For 'inout' params, if the resulting xpcom value is different than the + // one passed in, then we must release the incoming xpcom value. + nsISupports** variant = static_cast<nsISupports**>(aVariant.val.p); + if (aParamInfo.IsIn() && *variant) { + nsCOMPtr<nsISupports> in = do_QueryInterface(*variant); + nsCOMPtr<nsISupports> out = do_QueryInterface((nsISupports*) xpcom_obj); + if (in != out) { + NS_RELEASE(*variant); + } + } + + *(static_cast<void**>(aVariant.val.p)) = xpcom_obj; + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper"); + if (!aParamInfo.IsDipper()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = (jstring) aJValue.l; + nsString* variant = static_cast<nsString*>(aVariant.val.p); + + if (jstr) { + // Get string buffer + const jchar* wchar_ptr = env->GetStringChars(jstr, nsnull); + if (!wchar_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + variant->Assign(wchar_ptr); + + // release String buffer + env->ReleaseStringChars(jstr, wchar_ptr); + } else { + variant->SetIsVoid(PR_TRUE); + } + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper"); + if (!aParamInfo.IsDipper()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = (jstring) aJValue.l; + nsCString* variant = static_cast<nsCString*>(aVariant.val.p); + + if (jstr) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(jstr, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + variant->Assign(char_ptr); + + // release String buffer + env->ReleaseStringUTFChars(jstr, char_ptr); + } else { + variant->SetIsVoid(PR_TRUE); + } + } + break; + + case nsXPTType::T_VOID: + { + if (aParamInfo.IsRetval()) { // 'retval' + aVariant.val.p = reinterpret_cast<void*>(aJValue.j); + } else if (aJValue.l) { // 'inout' & 'out' + env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1, + (jlong*) aVariant.val.p); + } + } + break; + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +NS_IMETHODIMP +nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr) +{ + if (mMaster) + return mMaster->GetWeakReference(aInstancePtr); + + LOG(("==> nsJavaXPTCStub::GetWeakReference()\n")); + + if (!aInstancePtr) + return NS_ERROR_NULL_POINTER; + + jobject javaObject = GetJNIEnv()->CallObjectMethod(mJavaWeakRef, + getReferentMID); + nsJavaXPTCStubWeakRef* weakref; + weakref = new nsJavaXPTCStubWeakRef(javaObject, this); + if (!weakref) + return NS_ERROR_OUT_OF_MEMORY; + + *aInstancePtr = weakref; + NS_ADDREF(*aInstancePtr); + ++mWeakRefCnt; + + return NS_OK; +} + +jobject +nsJavaXPTCStub::GetJavaObject() +{ + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + return javaObject; +} + + +/*static*/ nsresult +nsJavaXPTCStub::GetNewOrUsed(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult) +{ + nsJavaXPTCStub* stub; + jint hash = env->CallStaticIntMethod(systemClass, hashCodeMID, aJavaObject); + nsresult rv = gJavaToXPTCStubMap->Find(hash, aIID, &stub); + NS_ENSURE_SUCCESS(rv, rv); + if (stub) { + // stub is already AddRef'd and QI'd + *aResult = stub; + return NS_OK; + } + + // If there is no corresponding XPCOM object, then that means that the + // parameter is a non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get interface info for class + nsCOMPtr<nsIInterfaceInfoManager> + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIInterfaceInfo> iinfo; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + NS_ENSURE_SUCCESS(rv, rv); + + // Create XPCOM stub + stub = new nsJavaXPTCStub(aJavaObject, iinfo, &rv); + if (!stub) + return NS_ERROR_OUT_OF_MEMORY; + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + rv = gJavaToXPTCStubMap->Add(hash, stub); + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + NS_ADDREF(stub); + *aResult = stub; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h new file mode 100644 index 00000000..90d42c8f --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h @@ -0,0 +1,153 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsJavaXPTCStub_h_ +#define _nsJavaXPTCStub_h_ + +#include "nsXPTCUtils.h" +#include "jni.h" +#include "nsVoidArray.h" +#include "nsIInterfaceInfo.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsJavaXPTCStubWeakRef.h" + + +#define NS_JAVAXPTCSTUB_IID \ +{0x88dd8130, 0xebe6, 0x4431, {0x9d, 0xa7, 0xe6, 0xb7, 0x54, 0x74, 0xfb, 0x21}} + +class nsJavaXPTCStub : protected nsAutoXPTCStub, + public nsSupportsWeakReference +{ + friend class nsJavaXPTCStubWeakRef; + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSWEAKREFERENCE + NS_DECLARE_STATIC_IID_ACCESSOR(NS_JAVAXPTCSTUB_IID) + + nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo, + nsresult *rv); + + virtual ~nsJavaXPTCStub(); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aInfo, + nsXPTCMiniVariant *aParams); + + nsISomeInterface* GetStub() { return mXPTCStub; } + + // getter for mJavaObject + jobject GetJavaObject(); + + // Deletes the strong global ref for the Java object, so it can be garbage + // collected if necessary. See DestroyXPTCMappingEnum(). + void DeleteStrongRef(); + + /** + * Finds the associated nsJavaXPTCStub for the given Java object and IID. + * If no such stub exists, then a new one is created. + * + * @param env Java environment pointer + * @param aJavaObject Java object for which to find/create nsJavaXPTCStub + * @param aIID desired interface IID for nsJavaXPTCStub + * @param aResult on success, holds AddRef'd reference to nsJavaXPTCStub + * + * @return NS_OK if succeeded; all other return values are error codes. + */ + static nsresult GetNewOrUsed(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult); + + +private: + NS_IMETHOD_(nsrefcnt) AddRefInternal(); + NS_IMETHOD_(nsrefcnt) ReleaseInternal(); + + // Deletes this object and its members. Called by ReleaseInternal() and + // ReleaseWeakRef(). + void Destroy(); + + // When a nsJavaXPTCStubWeakRef associated with this object is released, it + // calls this function to let this object know that there is one less weak + // ref. If there are no more weakrefs referencing this object, and no one + // holds a strong ref, then this function takes care of deleting the object. + void ReleaseWeakRef(); + + // returns a weak reference to a child supporting the specified interface + nsJavaXPTCStub * FindStubSupportingIID(const nsID &aIID); + + // returns true if this stub supports the specified interface + PRBool SupportsIID(const nsID &aIID); + + nsresult SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue, nsACString &aMethodSig); + nsresult GetRetvalSig(const nsXPTParamInfo* aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsACString &aRetvalSig); + nsresult FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue); + nsresult SetXPCOMRetval(); + + jobject mJavaWeakRef; + jobject mJavaStrongRef; + jint mJavaRefHashCode; + nsCOMPtr<nsIInterfaceInfo> mIInfo; + + nsVoidArray mChildren; // weak references (cleared by the children) + nsJavaXPTCStub *mMaster; // strong reference + + nsAutoRefCnt mWeakRefCnt; // count for number of associated weak refs +}; + +#ifdef VBOX +NS_DEFINE_STATIC_IID_ACCESSOR2(nsJavaXPTCStub, NS_JAVAXPTCSTUB_IID) +#else +NS_DEFINE_STATIC_IID_ACCESSOR2(nsJavaXPTCStub, NS_JAVAXPTCSTUB_IID) +#endif + +#endif // _nsJavaXPTCStub_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp new file mode 100644 index 00000000..cb98fc9b --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp @@ -0,0 +1,98 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "jni.h" +#include "nsJavaXPTCStubWeakRef.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsIInterfaceInfoManager.h" + + +/** + * How we handle XPCOM weak references to a Java object: + * + * If XPCOM requires or asks for a weak reference of a Java object, we first + * find (or create) an nsJavaXPTCStub for that Java object. That way, there is + * always an nsJavaXPTCStub for any nsJavaXPTCStubWeakRef. However, the + * XPTCStub may not always be 'valid'; that is, its refcount may be zero if + * is not currently referenced by any XPCOM class. + * When an XPCOM method queries the referent from the weak reference, the + * weak ref checks first whether the Java object is still valid. If so, we can + * immediately return an addref'd nsJavaXPTCStub. The XPTCStub takes care of + * finding an XPTCStub for the required IID. + */ + +nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(jobject aJavaObject, + nsJavaXPTCStub* aXPTCStub) + : mXPTCStub(aXPTCStub) +{ + JNIEnv* env = GetJNIEnv(); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mWeakRef = env->NewGlobalRef(weakref); +} + +nsJavaXPTCStubWeakRef::~nsJavaXPTCStubWeakRef() +{ + JNIEnv* env = GetJNIEnv(); + env->CallVoidMethod(mWeakRef, clearReferentMID); + env->DeleteGlobalRef(mWeakRef); + mXPTCStub->ReleaseWeakRef(); +} + +NS_IMPL_ADDREF(nsJavaXPTCStubWeakRef) +NS_IMPL_RELEASE(nsJavaXPTCStubWeakRef) + +NS_IMPL_QUERY_INTERFACE1(nsJavaXPTCStubWeakRef, nsIWeakReference) + +NS_IMETHODIMP +nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr) +{ + LOG(("nsJavaXPTCStubWeakRef::QueryReferent()\n")); + + // Is weak ref still valid? + // We create a strong local ref to make sure Java object isn't garbage + // collected during this call. + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mWeakRef, getReferentMID); + if (env->IsSameObject(javaObject, NULL)) + return NS_ERROR_NULL_POINTER; + + // Java object has not been garbage collected, so return QI from XPTCStub. + return mXPTCStub->QueryInterface(aIID, aInstancePtr); +} + diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h new file mode 100644 index 00000000..b538eecb --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef _nsJavaXPTCStubWeakRef_h_ +#define _nsJavaXPTCStubWeakRef_h_ + +#include "jni.h" +#include "nsIWeakReference.h" + + +class nsJavaXPTCStub; + +/** + * This class represents an XPCOM weak reference to a Java object. + */ +class nsJavaXPTCStubWeakRef : public nsIWeakReference +{ +public: + nsJavaXPTCStubWeakRef(jobject aJavaObject, nsJavaXPTCStub* aXPTCStub); + virtual ~nsJavaXPTCStubWeakRef(); + NS_DECL_ISUPPORTS + NS_DECL_NSIWEAKREFERENCE + +protected: + jobject mWeakRef; + nsJavaXPTCStub* mXPTCStub; +}; + +#endif // _nsJavaXPTCStubWeakRef_h_ diff --git a/src/libs/xpcom18a4/java/src/nsThreadUtils.h b/src/libs/xpcom18a4/java/src/nsThreadUtils.h new file mode 100644 index 00000000..53f3dbdb --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsThreadUtils.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@meer.net> + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef nsThreadUtils_h__ +#define nsThreadUtils_h__ + + +#ifdef VBOX +#include "nsIThread.h" + +inline already_AddRefed<nsIThread> +do_GetMainThread() { + nsIThread *thread = nsnull; + nsIThread::GetMainThread(&thread); + return already_AddRefed<nsIThread>(thread); +} + +#include "VBox/com/NativeEventQueue.h" + +inline already_AddRefed<nsIEventQueue> do_GetMainThreadQueue() +{ + com::NativeEventQueue* eq = com::NativeEventQueue::getMainEventQueue(); + NS_ASSERTION(eq != nsnull, "Must be valid"); + return eq->getIEventQueue(); +} + +#else +#include "prthread.h" +#include "prinrval.h" +#include "nsIThreadManager.h" +#include "nsIThread.h" +#include "nsIRunnable.h" +#include "nsStringGlue.h" +#include "nsCOMPtr.h" + + +// This is needed on some systems to prevent collisions between the symbols +// appearing in xpcom_core and xpcomglue. It may be unnecessary in the future +// with better toolchain support. +#ifdef MOZILLA_INTERNAL_API +# define NS_NewThread NS_NewThread_P +# define NS_GetCurrentThread NS_GetCurrentThread_P +# define NS_GetMainThread NS_GetMainThread_P +# define NS_IsMainThread NS_IsMainThread_P +# define NS_DispatchToCurrentThread NS_DispatchToCurrentThread_P +# define NS_DispatchToMainThread NS_DispatchToMainThread_P +# define NS_ProcessPendingEvents NS_ProcessPendingEvents_P +# define NS_HasPendingEvents NS_HasPendingEvents_P +# define NS_ProcessNextEvent NS_ProcessNextEvent_P +#endif + +//----------------------------------------------------------------------------- +// These methods are alternatives to the methods on nsIThreadManager, provided +// for convenience. + +/** + * Create a new thread, and optionally provide an initial event for the thread. + * + * @param result + * The resulting nsIThread object. + * @param initialEvent + * The initial event to run on this thread. This parameter may be null. + * + * @returns NS_ERROR_INVALID_ARG + * Indicates that the given name is not unique. + */ +extern NS_COM_GLUE NS_METHOD +NS_NewThread(nsIThread **result, nsIRunnable *initialEvent = nsnull); + +/** + * Get a reference to the current thread. + * + * @param result + * The resulting nsIThread object. + */ +extern NS_COM_GLUE NS_METHOD +NS_GetCurrentThread(nsIThread **result); + +/** + * Get a reference to the main thread. + * + * @param result + * The resulting nsIThread object. + */ +extern NS_COM_GLUE NS_METHOD +NS_GetMainThread(nsIThread **result); + +/** + * Test to see if the current thread is the main thread. + * + * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE + * otherwise. + */ +extern NS_COM_GLUE NS_METHOD_(PRBool) +NS_IsMainThread(); + +/** + * Dispatch the given event to the current thread. + * + * @param event + * The event to dispatch. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern NS_COM_GLUE NS_METHOD +NS_DispatchToCurrentThread(nsIRunnable *event); + +/** + * Dispatch the given event to the main thread. + * + * @param event + * The event to dispatch. + * @param dispatchFlags + * The flags to pass to the main thread's dispatch method. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern NS_COM_GLUE NS_METHOD +NS_DispatchToMainThread(nsIRunnable *event, + PRUint32 dispatchFlags = NS_DISPATCH_NORMAL); + +#ifndef XPCOM_GLUE_AVOID_NSPR +/** + * Process all pending events for the given thread before returning. This + * method simply calls ProcessNextEvent on the thread while HasPendingEvents + * continues to return true and the time spent in NS_ProcessPendingEvents + * does not exceed the given timeout value. + * + * @param thread + * The thread object for which to process pending events. If null, then + * events will be processed for the current thread. + * @param timeout + * The maximum number of milliseconds to spend processing pending events. + * Events are not pre-empted to honor this timeout. Rather, the timeout + * value is simply used to determine whether or not to process another event. + * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout. + */ +extern NS_COM_GLUE NS_METHOD +NS_ProcessPendingEvents(nsIThread *thread, + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT); +#endif + +/** + * Shortcut for nsIThread::HasPendingEvents. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will return PR_FALSE if called from some + * other thread. + * + * @param thread + * The current thread or null. + * + * @returns + * A boolean value that if "true" indicates that there are pending events + * in the current thread's event queue. + */ +extern NS_COM_GLUE PRBool +NS_HasPendingEvents(nsIThread *thread = nsnull); + +/** + * Shortcut for nsIThread::ProcessNextEvent. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will simply return PR_FALSE if called + * from some other thread. + * + * @param thread + * The current thread or null. + * @param mayWait + * A boolean parameter that if "true" indicates that the method may block + * the calling thread to wait for a pending event. + * + * @returns + * A boolean value that if "true" indicates that an event from the current + * thread's event queue was processed. + */ +extern NS_COM_GLUE PRBool +NS_ProcessNextEvent(nsIThread *thread = nsnull, PRBool mayWait = PR_TRUE); + +//----------------------------------------------------------------------------- +// Helpers that work with nsCOMPtr: + +inline already_AddRefed<nsIThread> +do_GetCurrentThread() { + nsIThread *thread = nsnull; + NS_GetCurrentThread(&thread); + return already_AddRefed<nsIThread>(thread); +} + +inline already_AddRefed<nsIThread> +do_GetMainThread() { + nsIThread *thread = nsnull; + NS_GetMainThread(&thread); + return already_AddRefed<nsIThread>(thread); +} + +//----------------------------------------------------------------------------- + +#ifdef MOZILLA_INTERNAL_API +// Fast access to the current thread. Do not release the returned pointer! If +// you want to use this pointer from some other thread, then you will need to +// AddRef it. Otherwise, you should only consider this pointer valid from code +// running on the current thread. +extern NS_COM_GLUE nsIThread *NS_GetCurrentThread(); +#endif + +//----------------------------------------------------------------------------- + +#ifndef XPCOM_GLUE_AVOID_NSPR + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_COM_GLUE + +// This class is designed to be subclassed. +class NS_COM_GLUE nsRunnable : public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + nsRunnable() { + } + +protected: + virtual ~nsRunnable() { + } +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +// An event that can be used to call a method on a class. The class type must +// support reference counting. +template <class T> +class nsRunnableMethod : public nsRunnable +{ +public: + typedef void (T::*Method)(); + + nsRunnableMethod(T *obj, Method method) + : mObj(obj), mMethod(method) { + NS_ADDREF(mObj); + } + + NS_IMETHOD Run() { + (mObj->*mMethod)(); + return NS_OK; + } + +private: + virtual ~nsRunnableMethod() { + NS_RELEASE(mObj); + } + + T *mObj; + Method mMethod; +}; + +// Use this helper macro like so: +// +// nsCOMPtr<nsIRunnable> event = +// NS_NEW_RUNNABLE_METHOD(MyClass, myObject, HandleEvent); +// NS_DispatchToCurrentThread(event); +// +// Constraints: +// - myObject must be of type MyClass +// - MyClass must defined AddRef and Release methods +// +// NOTE: Attempts to make this a template function caused VC6 to barf :-( +// +#define NS_NEW_RUNNABLE_METHOD(class_, obj_, method_) \ + new nsRunnableMethod<class_>(obj_, &class_::method_) + +#endif // XPCOM_GLUE_AVOID_NSPR + +// This class is designed to be used when you have an event class E that has a +// pointer back to resource class R. If R goes away while E is still pending, +// then it is important to "revoke" E so that it does not try use R after R has +// been destroyed. nsRevocableEventPtr makes it easy for R to manage such +// situations: +// +// class R; +// +// class E : public nsRunnable { +// public: +// void Revoke() { +// mResource = nsnull; +// } +// private: +// R *mResource; +// }; +// +// class R { +// public: +// void EventHandled() { +// mEvent.Forget(); +// } +// private: +// nsRevocableEventPtr<E> mEvent; +// }; +// +// void R::PostEvent() { +// // Make sure any pending event is revoked. +// mEvent->Revoke(); +// +// nsCOMPtr<nsIRunnable> event = new E(); +// if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) { +// // Keep pointer to event so we can revoke it. +// mEvent = event; +// } +// } +// +// NS_IMETHODIMP E::Run() { +// if (!mResource) +// return NS_OK; +// ... +// mResource->EventHandled(); +// return NS_OK; +// } +// +template <class T> +class nsRevocableEventPtr { +public: + nsRevocableEventPtr() + : mEvent(nsnull) { + } + + ~nsRevocableEventPtr() { + Revoke(); + } + + const nsRevocableEventPtr& operator=(T *event) { + Revoke(); + mEvent = event; + return *this; + } + + void Revoke() { + if (mEvent) { + mEvent->Revoke(); + mEvent = nsnull; + } + } + + void Forget() { + mEvent = nsnull; + } + + PRBool IsPending() { + return mEvent != nsnull; + } + +private: + // Not implemented + nsRevocableEventPtr(const nsRevocableEventPtr&); + nsRevocableEventPtr& operator=(const nsRevocableEventPtr&); + + T *mEvent; +}; +#endif + +#endif // nsThreadUtils_h__ diff --git a/src/libs/xpcom18a4/java/src/nsXPTCUtils.h b/src/libs/xpcom18a4/java/src/nsXPTCUtils.h new file mode 100644 index 00000000..9a1fe3cc --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsXPTCUtils.h @@ -0,0 +1,128 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation <http://www.mozilla.org/>. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Benjamin Smedberg <benjamin@smedbergs.us> - New code + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +#ifndef nsXPTCUtils_h__ +#define nsXPTCUtils_h__ + +#include "xptcall.h" + +#ifdef VBOX + +#define NS_DECLARE_STATIC_IID_ACCESSOR(the_iid) \ + template <class Dummy> \ + struct COMTypeInfo \ + { \ + static const nsIID kIID NS_HIDDEN; \ + }; \ + static const nsIID& GetIID() {return COMTypeInfo<int>::kIID;} + + +#define NS_DEFINE_STATIC_IID_ACCESSOR2(the_interface, the_iid) \ + template <class Dummy> \ + const nsIID the_interface::COMTypeInfo<Dummy>::kIID NS_HIDDEN = the_iid; + + +class nsIXPTCProxy : public nsISupports +{ +public: + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aInfo, + nsXPTCMiniVariant *aParams) = 0; +}; + +/** + * This is a typedef to avoid confusion between the canonical + * nsISupports* that provides object identity and an interface pointer + * for inheriting interfaces that aren't known at compile-time. + */ +typedef nsISupports nsISomeInterface; + +/** + * Get a proxy object to implement the specified interface. + * + * @param aIID The IID of the interface to implement. + * @param aOuter An object to receive method calls from the proxy object. + * The stub forwards QueryInterface/AddRef/Release to the + * outer object. The proxy object does not hold a reference to + * the outer object; it is the caller's responsibility to + * ensure that this pointer remains valid until the stub has + * been destroyed. + * @param aStub Out parameter for the new proxy object. The object is + * not addrefed. The object never destroys itself. It must be + * explicitly destroyed by calling + * NS_DestroyXPTCallStub when it is no longer needed. + */ +XPTC_PUBLIC_API(nsresult) +NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, + nsISomeInterface* *aStub); + +/** + * Destroys an XPTCall stub previously created with NS_GetXPTCallStub. + */ +XPTC_PUBLIC_API(void) +NS_DestroyXPTCallStub(nsISomeInterface* aStub); + + +#endif + + +/** + * A helper class that initializes an xptcall helper at construction + * and releases it at destruction. + */ +class nsAutoXPTCStub : protected nsIXPTCProxy +{ +public: + nsISomeInterface* mXPTCStub; + +protected: + nsAutoXPTCStub() : mXPTCStub(nsnull) { } + + nsresult + InitStub(const nsIID& aIID) + { + return NS_GetXPTCallStub(aIID, this, &mXPTCStub); + } + + ~nsAutoXPTCStub() + { + if (mXPTCStub) + NS_DestroyXPTCallStub(mXPTCStub); + } +}; + +#endif // nsXPTCUtils_h__ diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java new file mode 100644 index 00000000..ede1a523 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java @@ -0,0 +1,80 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + + +public class GREVersionRange { + + private String lower; + private boolean lowerInclusive; + private String upper; + private boolean upperInclusive; + + public GREVersionRange(String aLower, boolean aLowerInclusive, + String aUpper, boolean aUpperInclusive) { + lower = aLower; + lowerInclusive = aLowerInclusive; + upper = aUpper; + upperInclusive = aUpperInclusive; + } + + public boolean check(String aVersion) { + VersionComparator comparator = new VersionComparator(); + int c = comparator.compare(aVersion, lower); + if (c < 0) { + return false; + } + + if (c == 0 && !lowerInclusive) { + return false; + } + + c = comparator.compare(aVersion, upper); + if (c > 0) { + return false; + } + + if (c == 0 && !upperInclusive) { + return false; + } + + return true; + } + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java new file mode 100644 index 00000000..633d8bbc --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java @@ -0,0 +1,92 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + + +/** + * Used by XPCOM's Directory Service to get file locations. + * <p> + * This interface is similar to <code>nsIDirectoryServiceProvider</code> and + * <code>nsIDirectoryServiceProvider2</code>, except that its methods use + * <code>java.io.File</code> instead of <code>nsIFile</code>. + * </p> + * + * @see Mozilla#initEmbedding + * @see Mozilla#initXPCOM + * @see <a href= + * "http://lxr.mozilla.org/mozilla/source/xpcom/io/nsIDirectoryService.idl"> + * nsIDirectoryServiceProvider </a> + * @see <a href= + * "http://lxr.mozilla.org/mozilla/source/xpcom/io/nsDirectoryServiceDefs.h"> + * Directory Service property names </a> + */ +public interface IAppFileLocProvider { + + /** + * Directory Service calls this when it gets the first request for + * a property or on every request if the property is not persistent. + * + * @param prop the symbolic name of the file + * @param persistent an array of length one used to supply the output value: + * <ul> + * <li><code>true</code> - The returned file will be + * cached by Directory Service. Subsequent requests for + * this prop will bypass the provider and use the cache. + * </li> + * <li><code>false</code> - The provider will be asked + * for this prop each time it is requested. </li> + * </ul> + * + * @return the file represented by the property + */ + File getFile(String prop, boolean[] persistent); + + /** + * Directory Service calls this when it gets a request for + * a property and the requested type is nsISimpleEnumerator. + * + * @param prop the symbolic name of the file list + * + * @return an array of file locations + */ + File[] getFiles(String prop); + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java new file mode 100644 index 00000000..ecf000fe --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java @@ -0,0 +1,127 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + + +public interface IGRE { + + /** + * Initializes libXUL for embedding purposes. + * <p> + * NOTE: This function must be called from the "main" thread. + * <p> + * NOTE: At the present time, this function may only be called once in + * a given process. Use <code>termEmbedding</code> to clean up and free + * resources allocated by <code>initEmbedding</code>. + * + * @param aLibXULDirectory The directory in which the libXUL shared library + * was found. + * @param aAppDirectory The directory in which the application components + * and resources can be found. This will map to + * the "resource:app" directory service key. + * @param aAppDirProvider A directory provider for the application. This + * provider will be aggregated by a libXUL provider + * which will provide the base required GRE keys. + * + * @throws XPCOMException if a failure occurred during initialization + */ + void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) throws XPCOMException; + + /** + * Terminates libXUL embedding. + * <p> + * NOTE: Release any references to XPCOM objects that you may be holding + * before calling this function. + */ + void termEmbedding(); + + /** + * Lock a profile directory using platform-specific semantics. + * + * @param aDirectory The profile directory to lock. + * + * @return A lock object. The directory will remain locked until the lock is + * released by invoking the <code>release</code> method, or by the + * termination of the JVM, whichever comes first. + * + * @throws XPCOMException if a failure occurred + */ + ProfileLock lockProfileDirectory(File aDirectory) throws XPCOMException; + + /** + * Fire notifications to inform the toolkit about a new profile. This + * method should be called after <code>initEmbedding</code> if the + * embedder wishes to run with a profile. + * <p> + * Normally the embedder should call <code>lockProfileDirectory</code> + * to lock the directory before calling this method. + * <p> + * NOTE: There are two possibilities for selecting a profile: + * <ul> + * <li> + * Select the profile before calling <code>initEmbedding</code>. + * The aAppDirProvider object passed to <code>initEmbedding</code> + * should provide the NS_APP_USER_PROFILE_50_DIR key, and + * may also provide the following keys: + * <ul> + * <li>NS_APP_USER_PROFILE_LOCAL_50_DIR + * <li>NS_APP_PROFILE_DIR_STARTUP + * <li>NS_APP_PROFILE_LOCAL_DIR_STARTUP + * </ul> + * In this scenario <code>notifyProfile</code> should be called + * immediately after <code>initEmbedding</code>. Component + * registration information will be stored in the profile and + * JS components may be stored in the fastload cache. + * </li> + * <li> + * Select a profile some time after calling <code>initEmbedding</code>. + * In this case the embedder must install a directory service + * provider which provides NS_APP_USER_PROFILE_50_DIR and optionally + * NS_APP_USER_PROFILE_LOCAL_50_DIR. Component registration information + * will be stored in the application directory and JS components will not + * fastload. + * </li> + * </ul> + */ + void notifyProfile(); + +} + + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java new file mode 100644 index 00000000..7b70caf9 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java @@ -0,0 +1,59 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +public interface IJavaXPCOMUtils { + + /** + * Returns a pointer to a C++ proxy object for the given Java object. + * + * @param aJavaObject Java object to encapsulate in C++ proxy + * @param aIID interface ID for requested proxy + * @return C pointer (as long) of new proxy + */ + long wrapJavaObject(Object aJavaObject, String aIID); + + /** + * Returns a Java proxy for the given C++ XPCOM object + * + * @param aXPCOMObject C++ XPCOM object to encapsulate in Java proxy + * @param aIID interface ID for requested proxy + * @return new Proxy + */ + Object wrapXPCOMObject(long aXPCOMObject, String aIID); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java new file mode 100644 index 00000000..b148e9a2 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + +public interface IMozilla { + + /** + * Initialize the Mozilla object with the given XULRunner path. All + * subsequent Mozilla method invocations be done against the given XULRunner + * version. + * + * @param aLibXULDirectory path of XULRunner build to use + * + * @throws XPCOMInitializationException if failure occurred during + * initialization + */ + void initialize(File aLibXULDirectory) throws XPCOMInitializationException; + + /** + * Return the native window handle for an AWT component. + * + * @param widget An AWT component (such as Canvas, Frame) that is backed by + * a real native window. + * @return the pointer to the native window (platform specific) + */ + long getNativeHandleFromAWT(Object widget); +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java new file mode 100644 index 00000000..ba2f11c7 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java @@ -0,0 +1,243 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Properties; +import java.util.StringTokenizer; + + +/** + * A simple parser for INI files. + */ +public class INIParser { + + private HashMap<String, Properties> mSections; + + /** + * Creates a new <code>INIParser</code> instance from the INI file at the + * given path. <code>aCharset</code> specifies the character encoding of + * the file. + * + * @param aFilename path of INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if <code>aFilename</code> does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(String aFilename, Charset aCharset) + throws FileNotFoundException, IOException { + initFromFile(new File(aFilename), aCharset); + } + + /** + * Creates a new <code>INIParser</code> instance from the INI file at the + * given path, which is assumed to be in the <code>UTF-8</code> charset. + * + * @param aFilename path of INI file to parse + * @throws FileNotFoundException if <code>aFilename</code> does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(String aFilename) throws FileNotFoundException, IOException { + initFromFile(new File(aFilename), Charset.forName("UTF-8")); + } + + /** + * Creates a new <code>INIParser</code> instance from the given file. + * <code>aCharset</code> specifies the character encoding of the file. + * + * @param aFile INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if <code>aFile</code> does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(File aFile, Charset aCharset) + throws FileNotFoundException, IOException { + initFromFile(aFile, aCharset); + } + + /** + * Creates a new <code>INIParser</code> instance from the given file, + * which is assumed to be in the <code>UTF-8</code> charset. + * + * @param aFile INI file to parse + * @throws FileNotFoundException if <code>aFile</code> does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(File aFile) throws FileNotFoundException, IOException { + initFromFile(aFile, Charset.forName("UTF-8")); + } + + /** + * Parses given INI file. + * + * @param aFile INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if <code>aFile</code> does not exist. + * @throws IOException if there is a problem reading the given file. + */ + private void initFromFile(File aFile, Charset aCharset) + throws FileNotFoundException, IOException { + FileInputStream fileStream = new FileInputStream(aFile); + InputStreamReader inStream = new InputStreamReader(fileStream, aCharset); + BufferedReader reader = new BufferedReader(inStream); + + mSections = new HashMap<String, Properties>(); + String currSection = null; + + String line; + while ((line = reader.readLine()) != null) { + // skip empty lines and comment lines + String trimmedLine = line.trim(); + if (trimmedLine.length() == 0 || trimmedLine.startsWith("#") + || trimmedLine.startsWith(";")) { + continue; + } + + // Look for section headers (i.e. "[Section]"). + if (line.startsWith("[")) { + /* + * We are looking for a well-formed "[Section]". If this header is + * malformed (i.e. "[Section" or "[Section]Moretext"), just skip it + * and go on to next well-formed section header. + */ + if (!trimmedLine.endsWith("]") || + trimmedLine.indexOf("]") != (trimmedLine.length() - 1)) { + currSection = null; + continue; + } + + // remove enclosing brackets + currSection = trimmedLine.substring(1, trimmedLine.length() - 1); + continue; + } + + // If we haven't found a valid section header, continue to next line + if (currSection == null) { + continue; + } + + StringTokenizer tok = new StringTokenizer(line, "="); + if (tok.countTokens() != 2) { // looking for value pairs + continue; + } + + Properties props = mSections.get(currSection); + if (props == null) { + props = new Properties(); + mSections.put(currSection, props); + } + props.setProperty(tok.nextToken(), tok.nextToken()); + } + + reader.close(); + } + + /** + * Returns an iterator over the section names available in the INI file. + * + * @return an iterator over the section names + */ + public Iterator getSections() { + return mSections.keySet().iterator(); + } + + /** + * Returns an iterator over the keys available within a section. + * + * @param aSection section name whose keys are to be returned + * @return an iterator over section keys, or <code>null</code> if no + * such section exists + */ + public Iterator getKeys(String aSection) { + /* + * Simple wrapper class to convert Enumeration to Iterator + */ + class PropertiesIterator implements Iterator { + private Enumeration e; + + public PropertiesIterator(Enumeration aEnum) { + e = aEnum; + } + + public boolean hasNext() { + return e.hasMoreElements(); + } + + public Object next() { + return e.nextElement(); + } + + public void remove() { + return; + } + } + + Properties props = mSections.get(aSection); + if (props == null) { + return null; + } + + return new PropertiesIterator(props.propertyNames()); + } + + /** + * Gets the string value for a particular section and key. + * + * @param aSection a section name + * @param aKey the key whose value is to be returned. + * @return string value of particular section and key + */ + public String getString(String aSection, String aKey) { + Properties props = mSections.get(aSection); + if (props == null) { + return null; + } + + return props.getProperty(aKey); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java new file mode 100644 index 00000000..8cfbfb30 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java @@ -0,0 +1,137 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; + + +public interface IXPCOM { + + /** + * Initializes XPCOM. You must call this method before proceeding + * to use XPCOM. + * + * @param aMozBinDirectory The directory containing the component + * registry and runtime libraries; + * or use <code>null</code> to use the working + * directory. + * + * @param aAppFileLocProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * <code>null</code> for the default behaviour. + * + * @return the service manager + * + * @throws XPCOMException <ul> + * <li> NS_ERROR_NOT_INITIALIZED - if static globals were not initialied, + * which can happen if XPCOM is reloaded, but did not completly + * shutdown. </li> + * <li> Other error codes indicate a failure during initialisation. </li> + * </ul> + */ + nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) throws XPCOMException; + + /** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @param aServMgr The service manager which was returned by initXPCOM. + * This will release servMgr. + * + * @throws XPCOMException if a failure occurred during termination + */ + void shutdownXPCOM(nsIServiceManager aServMgr) throws XPCOMException; + + /** + * Public Method to access to the service manager. + * + * @return the service manager + * + * @throws XPCOMException + */ + nsIServiceManager getServiceManager() throws XPCOMException; + + /** + * Public Method to access to the component manager. + * + * @return the component manager + * + * @throws XPCOMException + */ + nsIComponentManager getComponentManager() throws XPCOMException; + + /** + * Public Method to access to the component registration manager. + * + * @return the component registration manager + * + * @throws XPCOMException + */ + nsIComponentRegistrar getComponentRegistrar() throws XPCOMException; + + /** + * Public Method to create an instance of a nsILocalFile. + * + * @param aPath A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * @param aFollowLinks This attribute will determine if the nsLocalFile will + * auto resolve symbolic links. By default, this value + * will be false on all non unix systems. On unix, this + * attribute is effectively a noop. + * + * @return an instance of an nsILocalFile that points to given path + * + * @throws XPCOMException <ul> + * <li> NS_ERROR_FILE_UNRECOGNIZED_PATH - raised for unrecognized paths + * or relative paths (must supply full file path) </li> + * </ul> + */ + nsILocalFile newLocalFile(String aPath, boolean aFollowLinks) + throws XPCOMException; + + // #ifdef VBOX + int waitForEvents(long timeout); + // #endif VBOX +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java new file mode 100644 index 00000000..05314c90 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java @@ -0,0 +1,1079 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; +import org.mozilla.interfaces.nsISupports; + + +/** + * A singleton class which provides access to the Mozilla browser. Requires + * that XULRunner be installed on the user's system. + * <p> + * You would use to class to find a XULRunner installation, setup a profile (if + * necessary), and initialize embedding. A typical scenario would look like + * this: + * </p><pre> + * Mozilla mozilla = Mozilla.getInstance(); + * GREVersionRange[] range = new GREVersionRange[1]; + * range[0] = new GREVersionRange("1.8.0.*", false, "1.8.1.*", true); + * try { + * File grePath = Mozilla.getGREPathWithProperties(range, null); + * mozilla.initialize(grePath); + * profLock = mozilla.lockProfileDirectory(profileDir); + * // LocationProvider is a user class that implements IAppFileLocProvider + * LocationProvider locProvider = new LocationProvider(grePath, profileDir); + * mozilla.initEmbedding(grePath, grePath, locProvider); + * mozilla.notifyProfile(); + * } catch (XPCOMInitializationException xie) { + * // handle exception + * } catch (XPCOMException xe) { + * // handle exception + * } + * </pre> + * + * @see http://www.mozilla.org/projects/embedding/GRE.html + */ +public class Mozilla implements IMozilla, IGRE, IXPCOM, IJavaXPCOMUtils,XPCOMError { + + private static Mozilla mozillaInstance = new Mozilla(); + + private static final String JAVAXPCOM_JAR = "vboxjxpcom.jar"; + + private IMozilla mozilla = null; + private IGRE gre = null; + private IXPCOM xpcom = null; + private IJavaXPCOMUtils jxutils = null; + + /** + * @return + */ + public static Mozilla getInstance() { + return mozillaInstance; + } + + /** + * + */ + private Mozilla() { + } + + /** + * Locates the path of a GRE with the specified properties. This method + * will only return GREs that support Java embedding (looks for the + * presence of "javaxpcom.jar"). + * <p> + * Currently this uses a "first-fit" algorithm, it does not select + * the newest available GRE. + * + * @param aVersions An array of version ranges: if any version range + * matches, the GRE is considered acceptable. + * @param aProperties A list of GRE property/value pairs which must + * all be satisfied. This parameter is ignored on + * Macintosh, because of the manner in which the + * XUL frameworks are installed. + * + * @return A file object of the appropriate path. If + * the "local" GRE is specified (via the USE_LOCAL_GRE + * environment variable, for example), returns + * <code>null</code>. + * + * @throws FileNotFoundException if an appropriate GRE could not be found + */ + public static File getGREPathWithProperties(GREVersionRange[] aVersions, + Properties aProperties) throws FileNotFoundException { + File grePath = null; + + // if GRE_HOME is in the environment, use that GRE + String env = System.getProperty("GRE_HOME"); + if (env != null) { + try { + grePath = new File(env).getCanonicalFile(); + } catch (IOException e) { + throw new FileNotFoundException("cannot access GRE_HOME"); + } + if (!grePath.exists()) { + throw new FileNotFoundException("GRE_HOME doesn't exist"); + } + return grePath; + } + + // the Gecko bits that sit next to the application or in the PATH + env = System.getProperty("USE_LOCAL_GRE"); + if (env != null) { + return null; + } + + // Search for GRE in platform specific locations. We want a GRE that + // supports Java, so we look for the "javaxpcom" property by default. + if (aProperties == null) { + aProperties = new Properties(); + } + aProperties.setProperty("javaxpcom", "1"); + + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("mac os x")) { + grePath = getGREPathMacOSX(aVersions); + } else if (osName.startsWith("windows")) { + grePath = getGREPathWindows(aVersions, aProperties); + } else { + // assume everything else is Unix/Linux + grePath = getGREPathUnix(aVersions, aProperties); + } + + if (grePath == null) { + throw new FileNotFoundException("GRE not found"); + } + + return grePath; + } + + /** + * @param aVersions + * @return + */ + private static File getGREPathMacOSX(GREVersionRange[] aVersions) { + /* + * Check the application bundle first, for + * <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib. + */ + File grePath = findGREBundleFramework(); + if (grePath != null) { + return grePath; + } + + // Check ~/Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib + String home = System.getProperty("user.home"); + if (home != null) { + grePath = findGREFramework(home, aVersions); + if (grePath != null) { + return grePath; + } + } + + // Check /Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib + return findGREFramework("", aVersions); + } + + /** + * @return + */ + private static File findGREBundleFramework() { + /* + * Use reflection to get Apple's NSBundle class, which can be used + * to get the bundle's "Frameworks" directory. + */ + try { + URL[] urls = new URL[1]; + urls[0] = new File("/System/Library/Java/").toURI().toURL(); + ClassLoader loader = new URLClassLoader(urls); + Class<?> bundleClass = Class.forName("com.apple.cocoa.foundation.NSBundle", + true, loader); + + // Get the bundle for this app. If this is not executing from + // a bundle, this will return null. + Method mainBundleMethod = bundleClass.getMethod("mainBundle", (java.lang.Class[])null); + Object bundle = mainBundleMethod.invoke(null, (java.lang.Object[])null); + + if (bundle != null) { + // Get the path to the bundle's "Frameworks" directory + Method fwPathMethod = bundleClass.getMethod("privateFrameworksPath", + (java.lang.Class[])null); + String path = (String) fwPathMethod.invoke(bundle, (java.lang.Object[])null); + + // look for libxpcom.dylib + if (path.length() != 0) { + File xulDir = new File(path, "XUL.framework"); + if (xulDir.isDirectory()) { + File xpcomLib = new File(xulDir, "libxpcom.dylib"); + if (xpcomLib.canRead()) { + File grePath = xpcomLib.getCanonicalFile().getParentFile(); + + // Since GRE Properties aren't supported on Mac OS X, we check + // for the existence of the "javaxpcom.jar" file in the GRE. + File jar = new File(grePath, JAVAXPCOM_JAR); + if (jar.canRead()) { + // found GRE + return grePath; + } + } + } + } + } + } catch (Exception e) { } + + return null; + } + + /** + * @param aRootPath + * @param aVersions + * @return + */ + private static File findGREFramework(String aRootPath, + GREVersionRange[] aVersions) { + File frameworkDir = new File(aRootPath + + "/Library/Frameworks/XUL.framework/Versions"); + if (!frameworkDir.exists()) + return null; + + File[] files = frameworkDir.listFiles(); + for (int i = 0; i < files.length; i++) { + if (checkVersion(files[i].getName(), aVersions)) { + File xpcomLib = new File(files[i], "libxpcom.dylib"); + + // Since GRE Properties aren't supported on Mac OS X, we check + // for the existence of the "javaxpcom.jar" file in the GRE. + File jar = new File(files[i], JAVAXPCOM_JAR); + if (xpcomLib.canRead() && jar.canRead()) { + return files[i]; + } + } + } + + return null; + } + + /** + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathWindows(GREVersionRange[] aVersions, + Properties aProperties) { + /* + * Note the usage of the "Software\\mozilla.org\\GRE" subkey - this allows + * us to have multiple versions of GREs on the same machine by having + * subkeys such as 1.0, 1.1, 2.0 etc. under it. + * + * Please see http://www.mozilla.org/projects/embedding/GRE.html for + * more info. + */ + + final String greKey = "Software\\mozilla.org\\GRE"; + + // See if there is a GRE registered for the current user. + // If not, look for one on the system. + String key = "HKEY_CURRENT_USER" + "\\" + greKey; + File grePath = getGREPathFromRegKey(key, aVersions, aProperties); + if (grePath == null) { + key = "HKEY_LOCAL_MACHINE" + "\\" + greKey; + grePath = getGREPathFromRegKey(key, aVersions, aProperties); + } + + return grePath; + } + + /** + * @param aRegKey + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathFromRegKey(String aRegKey, + GREVersionRange[] aVersions, Properties aProperties) { + // create a temp file for the registry export + File tempFile; + try { + tempFile = File.createTempFile("jx_registry", null); + } catch (IOException e) { + // failed to create temp file. ABORT + return null; + } + + Process proc; + try { + proc = Runtime.getRuntime().exec("regedit /e " + "\"" + tempFile.getPath() + + "\" \"" + aRegKey + "\""); + proc.waitFor(); + } catch (Exception e) { + // Failed to run regedit.exe. Length of temp file is zero, and that's + // handled next. + } + + // If there is a key by that name in the registry, then the file length + // will not be zero. + File grePath = null; + if (tempFile.length() != 0) { + grePath = getGREPathFromRegistryFile(tempFile.getPath(), + aRegKey, aVersions, aProperties); + } + + tempFile.delete(); + return grePath; + } + + /** + * @param aFileName + * @param aCharset + * @param aKeyName + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathFromRegistryFile(String aFileName, + String aKeyName, GREVersionRange[] aVersions, + Properties aProperties) { + INIParser parser; + try { + parser = new INIParser(aFileName, Charset.forName("UTF-16")); + } catch (Exception e) { + // Problem reading from file. Bail out. + return null; + } + + Iterator sectionsIter = parser.getSections(); + while (sectionsIter.hasNext()) { + // get 'section' name, which will be a registry key name + String section = (String) sectionsIter.next(); + + // Skip over GRE key ("<root>\Software\mozilla.org\GRE") + int gre_len = aKeyName.length(); + if (section.length() <= gre_len) { + continue; + } + + // Get the GRE subkey; that is, everything after + // "<root>\Software\mozilla.org\GRE\" + String subkeyName = section.substring(gre_len + 1); + + // We are only interested in _immediate_ subkeys. We want + // "<root>\Software\mozilla.org\GRE\<version>" but not + // "<root>\Software\mozilla.org\GRE\<version>\<moretext>". + if (subkeyName.indexOf('\\') != -1) { + continue; + } + + // See if this registry key has a "Version" value, and if so, compare + // it to our desired versions. + String version = parser.getString(section, "\"Version\""); + if (version == null) { + continue; + } + // remove quotes around string + version = version.substring(1, version.length() - 1); + if (!checkVersion(version, aVersions)) { + continue; + } + + // All properties must match, keeping in mind that the propery/value + // pairs returned by regedit.exe have quotes around them. + if (aProperties != null) { + boolean ok = true; + Enumeration e = aProperties.propertyNames(); + while (ok && e.hasMoreElements()) { + String prop = (String) e.nextElement(); + String greValue = parser.getString(section, "\"" + prop + "\""); + if (greValue == null) { + // No such property is set for this GRE. Go on to next GRE. + ok = false; + } else { + // See if the value of the property for the GRE matches + // the given value. + String value = aProperties.getProperty(prop); + if (!greValue.equals("\"" + value + "\"")) { + ok = false; + } + } + } + if (!ok) { + continue; + } + } + + String pathStr = parser.getString(section, "\"GreHome\""); + if (pathStr != null) { + // remove quotes around string + pathStr = pathStr.substring(1, pathStr.length() - 1); + File grePath = new File(pathStr); + if (grePath.exists()) { + File xpcomLib = new File(grePath, "xpcom.dll"); + if (xpcomLib.canRead()) { + // found a good GRE + return grePath; + } + } + } + } + + return null; + } + + /** + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathUnix(GREVersionRange[] aVersions, + Properties aProperties) { + File grePath = null; + + String env = System.getProperty("MOZ_GRE_CONF"); + if (env != null) { + grePath = getPathFromConfigFile(env, aVersions, aProperties); + if (grePath != null) { + return grePath; + } + } + + final String greUserConfFile = ".gre.config"; + final String greUserConfDir = ".gre.d"; + final String greConfPath = "/etc/gre.conf"; + final String greConfDir = "/etc/gre.d"; + + env = System.getProperty("user.home"); + if (env != null) { + // Look in ~/.gre.config + grePath = getPathFromConfigFile(env + File.separator + greUserConfFile, + aVersions, aProperties); + if (grePath != null) { + return grePath; + } + + // Look in ~/.gre.d/*.conf + grePath = getPathFromConfigDir(env + File.separator + greUserConfDir, + aVersions, aProperties); + if (grePath != null) { + return grePath; + } + } + + // Look for a global /etc/gre.conf file + grePath = getPathFromConfigFile(greConfPath, aVersions, aProperties); + if (grePath != null) { + return grePath; + } + + // Look for a group of config files in /etc/gre.d/ + grePath = getPathFromConfigDir(greConfDir, aVersions, aProperties); + return grePath; + } + + /** + * @param aFileName + * @param aVersions + * @param aProperties + * @return + */ + private static File getPathFromConfigFile(String aFileName, + GREVersionRange[] aVersions, Properties aProperties) { + INIParser parser; + try { + parser = new INIParser(aFileName); + } catch (Exception e) { + // Problem reading from file. Bail out. + return null; + } + + Iterator sectionsIter = parser.getSections(); + while (sectionsIter.hasNext()) { + // get 'section' name, which will be a version string + String section = (String) sectionsIter.next(); + + // if this isn't one of the versions we are looking for, move + // on to next section + if (!checkVersion(section, aVersions)) { + continue; + } + + // all properties must match + if (aProperties != null) { + boolean ok = true; + Enumeration e = aProperties.propertyNames(); + while (ok && e.hasMoreElements()) { + String prop = (String) e.nextElement(); + String greValue = parser.getString(section, prop); + if (greValue == null) { + // No such property is set for this GRE. Go on to next GRE. + ok = false; + } else { + // See if the value of the property for the GRE matches + // the given value. + if (!greValue.equals(aProperties.getProperty(prop))) { + ok = false; + } + } + } + if (!ok) { + continue; + } + } + + String pathStr = parser.getString(section, "GRE_PATH"); + if (pathStr != null) { + File grePath = new File(pathStr); + if (grePath.exists()) { + File xpcomLib = new File(grePath, "libxpcom.so"); + if (xpcomLib.canRead()) { + // found a good GRE + return grePath; + } + } + } + } + + return null; + } + + /** + * @param aDirName + * @param aVersions + * @param aProperties + * @return + */ + private static File getPathFromConfigDir(String aDirName, + GREVersionRange[] aVersions, Properties aProperties) { + /* + * Open the directory provided and try to read any files in that + * directory that end with .conf. We look for an entry that might + * point to the GRE that we're interested in. + */ + + File dir = new File(aDirName); + if (!dir.isDirectory()) { + return null; + } + + File grePath = null; + File[] files = dir.listFiles(); + for (int i = 0; i < files.length && grePath == null; i++) { + // only look for files that end in '.conf' + if (!files[i].getName().endsWith(".conf")) { + continue; + } + + grePath = getPathFromConfigFile(files[i].getPath(), aVersions, + aProperties); + } + + return grePath; + } + + /** + * @param aVersionToCheck + * @param aVersions + * @return + */ + private static boolean checkVersion(String aVersionToCheck, + GREVersionRange[] aVersions) { + for (int i = 0; i < aVersions.length; i++) { + if (aVersions[i].check(aVersionToCheck)) { + return true; + } + } + return false; + } + + /** + * Initialize the Mozilla object with the given XULRunner path. All + * subsequent Mozilla method invocations be done against the given XULRunner + * version. + * + * @param aLibXULDirectory path of XULRunner build to use + * + * @throws XPCOMInitializationException if failure occurred during + * initialization + */ + public void initialize(File aLibXULDirectory) + throws XPCOMInitializationException { + File jar = new File(aLibXULDirectory, JAVAXPCOM_JAR); + if (!jar.exists()) { + jar = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()); + if (!jar.exists()) + throw new XPCOMInitializationException("Could not find " + JAVAXPCOM_JAR + + " in " + aLibXULDirectory); + } + + URL[] urls = new URL[1]; + try { + urls[0] = jar.toURI().toURL(); + } catch (MalformedURLException e) { + throw new XPCOMInitializationException(e); + } + ClassLoader loader = new URLClassLoader(urls, + this.getClass().getClassLoader()); + + try { + Class mozillaClass = Class.forName("org.mozilla.xpcom.internal.MozillaImpl", + true, loader); + mozilla = (IMozilla) mozillaClass.newInstance(); + + Class greClass = Class.forName("org.mozilla.xpcom.internal.GREImpl", + true, loader); + gre = (IGRE) greClass.newInstance(); + + Class xpcomClass = Class.forName("org.mozilla.xpcom.internal.XPCOMImpl", + true, loader); + xpcom = (IXPCOM) xpcomClass.newInstance(); + + Class javaXPCOMClass = + Class.forName("org.mozilla.xpcom.internal.JavaXPCOMMethods", + true, loader); + jxutils = (IJavaXPCOMUtils) javaXPCOMClass.newInstance(); + } catch (Exception e) { + throw new XPCOMInitializationException("Could not load " + + "org.mozilla.xpcom.internal.* classes", e); + } + + mozilla.initialize(aLibXULDirectory); + } + + /** + * Initializes libXUL for embedding purposes. + * <p> + * NOTE: This function must be called from the "main" thread. + * <p> + * NOTE: At the present time, this function may only be called once in + * a given process. Use <code>termEmbedding</code> to clean up and free + * resources allocated by <code>initEmbedding</code>. + * + * @param aLibXULDirectory The directory in which the libXUL shared library + * was found. + * @param aAppDirectory The directory in which the application components + * and resources can be found. This will map to + * the "resource:app" directory service key. + * @param aAppDirProvider A directory provider for the application. This + * provider will be aggregated by a libXUL provider + * which will provide the base required GRE keys. + * + * @throws XPCOMException if a failure occurred during initialization + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) throws XPCOMException { + try { + gre.initEmbedding(aLibXULDirectory, aAppDirectory, aAppDirProvider); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Terminates libXUL embedding. + * <p> + * NOTE: Release any references to XPCOM objects that you may be holding + * before calling this function. + * + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void termEmbedding() { + try { + gre.termEmbedding(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } finally { + mozilla = null; + gre = null; + xpcom = null; + } + } + + /** + * Lock a profile directory using platform-specific semantics. + * + * @param aDirectory The profile directory to lock. + * + * @return A lock object. The directory will remain locked until the lock is + * released by invoking the <code>release</code> method, or by the + * termination of the JVM, whichever comes first. + * + * @throws XPCOMException if profile is already locked (with + * <code>errorcode</code> == <code>NS_ERROR_FILE_ACCESS_DENIED</code>); + * or if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public ProfileLock lockProfileDirectory(File aDirectory) + throws XPCOMException { + try { + return gre.lockProfileDirectory(aDirectory); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Fire notifications to inform the toolkit about a new profile. This + * method should be called after <code>initEmbedding</code> if the + * embedder wishes to run with a profile. + * <p> + * Normally the embedder should call <code>lockProfileDirectory</code> + * to lock the directory before calling this method. + * <p> + * NOTE: There are two possibilities for selecting a profile: + * <ul> + * <li> + * Select the profile before calling <code>initEmbedding</code>. + * The aAppDirProvider object passed to <code>initEmbedding</code> + * should provide the NS_APP_USER_PROFILE_50_DIR key, and + * may also provide the following keys: + * <ul> + * <li>NS_APP_USER_PROFILE_LOCAL_50_DIR + * <li>NS_APP_PROFILE_DIR_STARTUP + * <li>NS_APP_PROFILE_LOCAL_DIR_STARTUP + * </ul> + * In this scenario <code>notifyProfile</code> should be called + * immediately after <code>initEmbedding</code>. Component + * registration information will be stored in the profile and + * JS components may be stored in the fastload cache. + * </li> + * <li> + * Select a profile some time after calling <code>initEmbedding</code>. + * In this case the embedder must install a directory service + * provider which provides NS_APP_USER_PROFILE_50_DIR and optionally + * NS_APP_USER_PROFILE_LOCAL_50_DIR. Component registration information + * will be stored in the application directory and JS components will not + * fastload. + * </li> + * </ul> + * + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void notifyProfile() { + try { + gre.notifyProfile(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Initializes XPCOM. You must call this method before proceeding + * to use XPCOM. + * + * @param aMozBinDirectory The directory containing the component + * registry and runtime libraries; + * or use <code>null</code> to use the working + * directory. + * + * @param aAppFileLocProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * <code>null</code> for the default behaviour. + * + * @return the service manager + * + * @throws XPCOMException <ul> + * <li> NS_ERROR_NOT_INITIALIZED - if static globals were not initialied, + * which can happen if XPCOM is reloaded, but did not completly + * shutdown. </li> + * <li> Other error codes indicate a failure during initialisation. </li> + * </ul> + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) throws XPCOMException { + try { + return xpcom.initXPCOM(aMozBinDirectory, aAppFileLocProvider); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @param aServMgr The service manager which was returned by initXPCOM. + * This will release servMgr. + * + * @throws XPCOMException if a failure occurred during termination + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void shutdownXPCOM(nsIServiceManager aServMgr) throws XPCOMException { + try { + xpcom.shutdownXPCOM(aServMgr); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } finally { + mozilla = null; + gre = null; + xpcom = null; + } + } + + /** + * Public Method to access to the service manager. + * + * @return the service manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIServiceManager getServiceManager() throws XPCOMException { + try { + return xpcom.getServiceManager(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Public Method to access to the component manager. + * + * @return the component manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIComponentManager getComponentManager() throws XPCOMException { + try { + return xpcom.getComponentManager(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Public Method to access to the component registration manager. + * + * @return the component registration manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIComponentRegistrar getComponentRegistrar() throws XPCOMException { + try { + return xpcom.getComponentRegistrar(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + // #ifdef VBOX + public int waitForEvents(long tmo) throws XPCOMException { + try { + return xpcom.waitForEvents(tmo); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + // #endif // VBOX + + /** + * Public Method to create an instance of a nsILocalFile. + * + * @param aPath A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * @param aFollowLinks This attribute will determine if the nsLocalFile will + * auto resolve symbolic links. By default, this value + * will be false on all non unix systems. On unix, this + * attribute is effectively a noop. + * + * @return an instance of an nsILocalFile that points to given path + * + * @throws XPCOMException <ul> + * <li> NS_ERROR_FILE_UNRECOGNIZED_PATH - raised for unrecognized paths + * or relative paths (must supply full file path) </li> + * </ul> + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsILocalFile newLocalFile(String aPath, boolean aFollowLinks) + throws XPCOMException { + try { + return xpcom.newLocalFile(aPath, aFollowLinks); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * If you create a class that implements nsISupports, you will need to provide + * an implementation of the <code>queryInterface</code> method. This helper + * function provides a simple implementation. Therefore, if your class does + * not need to do anything special with <code>queryInterface</code>, your + * implementation would look like: + * <pre> + * public nsISupports queryInterface(String aIID) { + * return XPCOM.queryInterface(this, aIID); + * } + * </pre> + * + * @param aObject object to query + * @param aIID requested interface IID + * + * @return <code>aObject</code> if the given object supports that + * interface; + * <code>null</code> otherwise. + */ + public static nsISupports queryInterface(nsISupports aObject, String aIID) { + ArrayList<Class> classes = new ArrayList<Class>(); + classes.add(aObject.getClass()); + + while (!classes.isEmpty()) { + Class clazz = classes.remove(0); + + // Skip over any class/interface in the "java.*" and "javax.*" domains. + String className = clazz.getName(); + if (className.startsWith("java.") || className.startsWith("javax.")) { + continue; + } + + // If given IID matches that of the current interface, then we + // know that aObject implements the interface specified by the given IID. + if (clazz.isInterface() && className.startsWith("org.mozilla")) { + String iid = Mozilla.getInterfaceIID(clazz); + if (iid != null && aIID.equals(iid)) { + return aObject; + } + } + + // clazz didn't match, so add the interfaces it implements + Class[] interfaces = clazz.getInterfaces(); + for (int i = 0; i < interfaces.length; i++ ) { + classes.add(interfaces[i]); + } + + // Also add its superclass + Class superclass = clazz.getSuperclass(); + if (superclass != null) { + classes.add(superclass); + } + } + + return null; + } + + /** + * Gets the interface IID for a particular Java interface. This is similar + * to NS_GET_IID in the C++ Mozilla files. + * + * @param aInterface interface which has defined an IID + * + * @return IID for given interface + */ + public static String getInterfaceIID(Class aInterface) { + // Get short class name (i.e. "bar", not "org.blah.foo.bar") + StringBuffer iidName = new StringBuffer(); + String fullClassName = aInterface.getName(); + int index = fullClassName.lastIndexOf("."); + String className = index > 0 ? fullClassName.substring(index + 1) + : fullClassName; + + // Create iid field name + if (className.startsWith("ns")) { + iidName.append("NS_"); + iidName.append(className.substring(2).toUpperCase()); + } else { + iidName.append(className.toUpperCase()); + } + iidName.append("_IID"); + + String iid; + try { + Field iidField = aInterface.getDeclaredField(iidName.toString()); + iid = (String) iidField.get(null); + } catch (NoSuchFieldException e) { + // Class may implement non-Mozilla interfaces, which would not have an + // IID method. In that case, just null. + iid = null; + } catch (IllegalAccessException e) { + // Not allowed to access that field for some reason. Write out an + // error message, but don't fail. + System.err.println("ERROR: Could not get field " + iidName.toString()); + iid = null; + } + + return iid; + } + + public long getNativeHandleFromAWT(Object widget) { + try { + return mozilla.getNativeHandleFromAWT(widget); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + public long wrapJavaObject(Object aJavaObject, String aIID) { + try { + return jxutils.wrapJavaObject(aJavaObject, aIID); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + public Object wrapXPCOMObject(long aXPCOMObject, String aIID) { + try { + return jxutils.wrapXPCOMObject(aXPCOMObject, aIID); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java new file mode 100644 index 00000000..f995a389 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +public class ProfileLock { + + private long lock = 0; + + public ProfileLock(long aLockObject) { + lock = aLockObject; + } + + public void release() { + releaseNative(lock); + lock = 0; + } + + private native void releaseNative(long aLockObject); + + public boolean isValid() { + return lock != 0; + } + + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java new file mode 100644 index 00000000..f9fb1058 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java @@ -0,0 +1,272 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + +import java.util.Enumeration; +import java.util.StringTokenizer; + +import org.mozilla.interfaces.nsISupports; +/* import org.mozilla.interfaces.nsIVersionComparator; */ + + +/** + * Version strings are dot-separated sequences of version-parts. + * <p> + * A version-part consists of up to four parts, all of which are optional: + * <br><code> + * <number-a><string-b><number-c> + * <string-d (everything else)> + * </code> <p> + * A version-part may also consist of a single asterisk "*" which indicates + * "infinity". + * <p> + * Numbers are base-10, and are zero if left out. + * Strings are compared bytewise. + * <p> + * For additional backwards compatibility, if "string-b" is "+" then + * "number-a" is incremented by 1 and "string-b" becomes "pre". + * <p> <pre> + * 1.0pre1 + * < 1.0pre2 + * < 1.0 == 1.0.0 == 1.0.0.0 + * < 1.1pre == 1.1pre0 == 1.0+ + * < 1.1pre1a + * < 1.1pre1 + * < 1.1pre10a + * < 1.1pre10 + * </pre> + * Although not required by this interface, it is recommended that + * numbers remain within the limits of a signed char, i.e. -127 to 128. + */ +public class VersionComparator implements nsISupports /* implements nsIVersionComparator */ { + + public nsISupports queryInterface(String aIID) { + return Mozilla.queryInterface(this, aIID); + } + + /** + * Compare two version strings + * @param A a version string + * @param B a version string + * @return a value less than 0 if A < B; + * the value 0 if A == B; + * or a value greater than 0 if A > B + */ + public int compare(String A, String B) { + int result; + String a = A, b = B; + + do { + VersionPart va = new VersionPart(); + VersionPart vb = new VersionPart(); + a = parseVersionPart(a, va); + b = parseVersionPart(b, vb); + + result = compareVersionPart(va, vb); + if (result != 0) { + break; + } + } while (a != null || b != null); + + return result; + } + + private class VersionPart { + int numA = 0; + String strB; + int numC = 0; + String extraD; + } + + private static String parseVersionPart(String aVersion, VersionPart result) { + if (aVersion == null || aVersion.length() == 0) { + return aVersion; + } + + StringTokenizer tok = new StringTokenizer(aVersion.trim(), "."); + String part = tok.nextToken(); + + if (part.equals("*")) { + result.numA = Integer.MAX_VALUE; + result.strB = ""; + } else { + VersionPartTokenizer vertok = new VersionPartTokenizer(part); + try { + result.numA = Integer.parseInt(vertok.nextToken()); + } catch (NumberFormatException e) { + // parsing error; default to zero like 'strtol' C function + result.numA = 0; + } + + if (vertok.hasMoreElements()) { + String str = vertok.nextToken(); + + // if part is of type "<num>+" + if (str.charAt(0) == '+') { + result.numA++; + result.strB = "pre"; + } else { + // else if part is of type "<num><alpha>..." + result.strB = str; + + if (vertok.hasMoreTokens()) { + try { + result.numC = Integer.parseInt(vertok.nextToken()); + } catch (NumberFormatException e) { + // parsing error; default to zero like 'strtol' C function + result.numC = 0; + } + if (vertok.hasMoreTokens()) { + result.extraD = vertok.getRemainder(); + } + } + } + } + } + + if (tok.hasMoreTokens()) { + // return everything after "." + return aVersion.substring(part.length() + 1); + } + return null; + } + + private int compareVersionPart(VersionPart va, VersionPart vb) { + int res = compareInt(va.numA, vb.numA); + if (res != 0) { + return res; + } + + res = compareString(va.strB, vb.strB); + if (res != 0) { + return res; + } + + res = compareInt(va.numC, vb.numC); + if (res != 0) { + return res; + } + + return compareString(va.extraD, vb.extraD); + } + + private int compareInt(int n1, int n2) { + return n1 - n2; + } + + private int compareString(String str1, String str2) { + // any string is *before* no string + if (str1 == null) { + return (str2 != null) ? 1 : 0; + } + + if (str2 == null) { + return -1; + } + + return str1.compareTo(str2); + } + +} + +/** + * Specialized tokenizer for Mozilla version strings. A token can + * consist of one of the four sections of a version string: <code> + * <number-a><string-b><number-c> + * <string-d (everything else)></code>. + */ +class VersionPartTokenizer implements Enumeration { + + String part; + + public VersionPartTokenizer(String aPart) { + part = aPart; + } + + public boolean hasMoreElements() { + return part.length() != 0; + } + + public boolean hasMoreTokens() { + return part.length() != 0; + } + + public Object nextElement() { + if (part.matches("[\\+\\-]?[0-9].*")) { + // if string starts with a number... + int index = 0; + if (part.charAt(0) == '+' || part.charAt(0) == '-') { + index = 1; + } + + while (index < part.length() && Character.isDigit(part.charAt(index))) { + index++; + } + + String numPart = part.substring(0, index); + part = part.substring(index); + return numPart; + } else { + // ... or if this is the non-numeric part of version string + int index = 0; + while (index < part.length() && !Character.isDigit(part.charAt(index))) { + index++; + } + + String alphaPart = part.substring(0, index); + part = part.substring(index); + return alphaPart; + } + } + + public String nextToken() { + return (String) nextElement(); + } + + /** + * Returns what remains of the original string, without tokenization. This + * method is useful for getting the <code><string-d (everything else)> + * </code> section of a version string. + * + * @return remaining version string + */ + public String getRemainder() { + return part; + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java new file mode 100644 index 00000000..9eca58f6 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java @@ -0,0 +1,95 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + + +/** + * This exception is thrown whenever an internal XPCOM/Gecko error occurs. + * You can query the error ID returned by XPCOM by checking + * <code>errorcode</code> field. + */ +public class XPCOMException extends RuntimeException { + + /** + * The XPCOM error value. + */ + public long errorcode; + + private static final long serialVersionUID = 198521829884000593L; + + /** + * Constructs a new XPCOMException instance, with a default error + * (NS_ERROR_FAILURE) and message. + */ + public XPCOMException() { + this(0x80004005L, "Unspecified internal XPCOM error"); + } + + /** + * Constructs a new XPCOMException instance with the given message, passing + * NS_ERROR_FAILURE as the error code. + * + * @param message detailed message of exception + */ + public XPCOMException(String message) { + this(0x80004005L, message); + } + + /** + * Constructs a new XPCOMException instance with the given code, passing + * a default message. + * + * @param code internal XPCOM error ID + */ + public XPCOMException(long code) { + this(code, "Internal XPCOM error"); + } + + /** + * Constructs a new XPCOMException instance with an error code and message. + * + * @param code internal XPCOM error ID + * @param message detailed message of exception + */ + public XPCOMException(long code, String message) { + super(message + " (0x" + Long.toHexString(code) + ")"); + this.errorcode = code; + } + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java new file mode 100644 index 00000000..26ce5325 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java @@ -0,0 +1,56 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom; + + +public class XPCOMInitializationException extends RuntimeException { + + private static final long serialVersionUID = -7067350325909231055L; + + public XPCOMInitializationException(String message) { + super(message); + } + + public XPCOMInitializationException(Throwable cause) { + super(cause); + } + + public XPCOMInitializationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java new file mode 100644 index 00000000..74821c36 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IAppFileLocProvider; +import org.mozilla.xpcom.IGRE; +import org.mozilla.xpcom.ProfileLock; + + +public class GREImpl implements IGRE { + + public void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) { + initEmbeddingNative(aLibXULDirectory, aAppDirectory, aAppDirProvider); + } + + public native void initEmbeddingNative(File aLibXULDirectory, + File aAppDirectory, IAppFileLocProvider aAppDirProvider); + + public native void termEmbedding(); + + public native ProfileLock lockProfileDirectory(File aDirectory); + + public native void notifyProfile(); + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java new file mode 100644 index 00000000..ab0ca251 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java @@ -0,0 +1,104 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IJavaXPCOMUtils; + + +public class JavaXPCOMMethods implements IJavaXPCOMUtils { + + public static void registerJavaXPCOMMethods(File aLibXULDirectory) { + // load JNI library + String path = ""; + if (aLibXULDirectory != null) { + path = aLibXULDirectory + File.separator; + } + + if (false) + { + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("os/2")) { + System.load(path + System.mapLibraryName("jxpcmglu")); + } else { + System.load(path + System.mapLibraryName("javaxpcomglue")); + } + } else { + // #ifdef VBOX + try { + System.load(path + System.mapLibraryName("vboxjxpcom")); + } catch (java.lang.UnsatisfiedLinkError ule) { + System.loadLibrary("vboxjxpcom"); + } + // #endif + } + registerJavaXPCOMMethodsNative(aLibXULDirectory); + } + + public static native void + registerJavaXPCOMMethodsNative(File aLibXULDirectory); + + /** + * Returns the Class object associated with the class or interface with the + * given string name, using the class loader of the given object. + * + * @param aObject the Java object whose class loader is used to load class + * @param aClassName the fully qualified name of desired class + * @return the Class object of requested Class; <code>null</code> if the + * class was not found + * + * @see http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#classops + */ + public static Class findClassInLoader(Object aObject, String aClassName) { + try { + if (aObject == null) { + return Class.forName(aClassName); + } else { + return Class.forName(aClassName, true, + aObject.getClass().getClassLoader()); + } + } catch (ClassNotFoundException e) { + return null; + } + } + + public native long wrapJavaObject(Object aJavaObject, String aIID); + + public native Object wrapXPCOMObject(long aXPCOMObject, String aIID); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java new file mode 100644 index 00000000..27fd9482 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java @@ -0,0 +1,56 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IMozilla; +import org.mozilla.xpcom.XPCOMInitializationException; + +public class MozillaImpl implements IMozilla { + + public void initialize(File aLibXULDirectory) + throws XPCOMInitializationException { + JavaXPCOMMethods.registerJavaXPCOMMethods(aLibXULDirectory); + initializeNative(); + } + + private native void initializeNative(); + + public native long getNativeHandleFromAWT(Object widget); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java new file mode 100644 index 00000000..1111a9e0 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java @@ -0,0 +1,73 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IAppFileLocProvider; +import org.mozilla.xpcom.IXPCOM; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; + + +public class XPCOMImpl implements IXPCOM { + + public nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) { + return initXPCOMNative(aMozBinDirectory, aAppFileLocProvider); + } + + public native nsIServiceManager initXPCOMNative(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider); + + public native void shutdownXPCOM(nsIServiceManager aServMgr); + + public native nsIComponentManager getComponentManager(); + + public native nsIComponentRegistrar getComponentRegistrar(); + + public native nsIServiceManager getServiceManager(); + + public native nsILocalFile newLocalFile(String aPath, boolean aFollowLinks); + + // #ifdef VBOX + public native int waitForEvents(long timeout); + // #endif VBOX +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java new file mode 100644 index 00000000..c6485708 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java @@ -0,0 +1,257 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.mozilla.xpcom.XPCOMException; + + +/** + * This class is used to pass XPCOM objects to Java functions. A + * <code>java.lang.reflect.Proxy</code> instance is created using the expected + * interface, and all calls to the proxy are forwarded to the XPCOM object. + */ +public class XPCOMJavaProxy implements InvocationHandler { + + /** + * Pointer to the XPCOM object for which we are a proxy. + */ + protected long nativeXPCOMPtr; + + /** + * Default constructor. + * + * @param aXPCOMInstance address of XPCOM object as a long + */ + public XPCOMJavaProxy(long aXPCOMInstance) { + nativeXPCOMPtr = aXPCOMInstance; + } + + /** + * Returns the XPCOM object that the given proxy references. + * + * @param aProxy Proxy created by <code>createProxy</code> + * + * @return address of XPCOM object as a long + */ + protected static long getNativeXPCOMInstance(Object aProxy) { + XPCOMJavaProxy proxy = (XPCOMJavaProxy) Proxy.getInvocationHandler(aProxy); + return proxy.nativeXPCOMPtr; + } + + /** + * Creates a Proxy for the given XPCOM object. + * + * @param aInterface interface from which to create Proxy + * @param aXPCOMInstance address of XPCOM object as a long + * + * @return Proxy of given XPCOM object + */ + protected static Object createProxy(Class aInterface, long aXPCOMInstance) { + // XXX We should really get the class loader from |aInterface|. However, + // that class loader doesn't know about |XPCOMJavaProxyBase|. So for + // now, we get the class loader that loaded |XPCOMJavaProxy|. When + // we get rid of the "XPCOMJavaProxyBase.java" class, we can revert + // to the old method below. +// return Proxy.newProxyInstance(aInterface.getClassLoader(), + return Proxy.newProxyInstance(XPCOMJavaProxy.class.getClassLoader(), + new Class[] { aInterface, XPCOMJavaProxyBase.class }, + new XPCOMJavaProxy(aXPCOMInstance)); + } + + /** + * All calls to the Java proxy are forwarded to this method. This method + * takes care of a few of the <code>Object</code> method calls; all other + * calls are forwarded to the XPCOM object. + * + * @param aProxy Proxy created by <code>createProxy</code> + * @param aMethod object that describes the called method + * @param aParams array of the arguments passed to the method + * + * @return return value as defined by given <code>aMethod</code> + */ + public Object invoke(Object aProxy, Method aMethod, Object[] aParams) + throws Throwable { + String methodName = aMethod.getName(); + + // Handle the three java.lang.Object methods that are passed to us. + if (aMethod.getDeclaringClass() == Object.class) { + if (methodName.equals("hashCode")) { + return proxyHashCode(aProxy); + } + if (methodName.equals("equals")) { + return proxyEquals(aProxy, aParams[0]); + } + if (methodName.equals("toString")) { + return proxyToString(aProxy); + } + System.err.println("WARNING: Unhandled Object method [" + + methodName + "]"); + return null; + } + + // Handle the 'finalize' method called during garbage collection + if (aMethod.getDeclaringClass() == XPCOMJavaProxyBase.class) { + if (methodName.equals("finalize")) { + finalizeProxy(aProxy); + } else { + System.err.println("WARNING: Unhandled XPCOMJavaProxyBase method [" + + methodName + "]"); + } + return null; + } + + // If not already handled, pass method calls to XPCOM object. + return callXPCOMMethod(aProxy, methodName, aParams); + } + + /** + * Handles method calls of <code>java.lang.Object.hashCode</code> + * + * @param aProxy Proxy created by <code>createProxy</code> + * + * @return Integer object representing hash code of given object + * + * @see Object#hashCode() + */ + protected static Integer proxyHashCode(Object aProxy) { + return new Integer(System.identityHashCode(aProxy)); + } + + /** + * Handles method calls of <code>java.lang.Object.equals</code> + * + * @param aProxy Proxy created by <code>createProxy</code> + * @param aOther another object + * + * @return <code>true</code> if the given objects are the same; + * <code>false</code> otherwise + * + * @see Object#equals(Object) + */ + protected static Boolean proxyEquals(Object aProxy, Object aOther) { + // See if the two are the same Java object + if (aProxy == aOther) { + return Boolean.TRUE; + } else { + // If not, then see if they represent the same XPCOM object. But first, + // we need to check if |aOther| is an XPCOMJavaProxy. + if (isXPCOMJavaProxy(aOther) && isSameXPCOMObject(aProxy, aOther)) { + return Boolean.TRUE; + } + } + return Boolean.FALSE; + } + + /** + * Indicates whether the given object is an XPCOMJavaProxy. + * + * @param aObject object to check + * + * @return <code>true</code> if the given object is an XPCOMJavaProxy; + * <code>false</code> otherwise + */ + protected static boolean isXPCOMJavaProxy(Object aObject) { + if (aObject != null && Proxy.isProxyClass(aObject.getClass())) { + InvocationHandler h = Proxy.getInvocationHandler(aObject); + if (h instanceof XPCOMJavaProxy) { + return true; + } + } + return false; + } + + /** + * Checks if the two given XPCOMJavaProxy objects are proxies for + * the same XPCOM object. + * + * @param aProxy1 XPCOMJavaProxy created by <code>createProxy</code> + * @param aProxy2 XPCOMJavaProxy created by <code>createProxy</code> + * + * @return <code>true</code> if both proxies represent the same XPCOM object; + * <code>false</code> otherwise + */ + protected static native boolean isSameXPCOMObject(Object aProxy1, + Object aProxy2); + + /** + * Handles method calls of <code>java.lang.Object.toString</code> + * + * @param aProxy Proxy created by <code>createProxy</code> + * + * @return String representation of given object + * + * @see Object#toString() + */ + protected static String proxyToString(Object aProxy) { + return aProxy.getClass().getInterfaces()[0].getName() + '@' + + Integer.toHexString(aProxy.hashCode()); + } + + /** + * Called when the proxy is garbage collected by the JVM. Allows us to clean + * up any references to the XPCOM object. + * + * @param aProxy reference to Proxy that is being garbage collected + */ + protected void finalizeProxy(Object aProxy) throws Throwable { + finalizeProxyNative(aProxy); + super.finalize(); + } + + protected static native void finalizeProxyNative(Object aProxy); + + /** + * Calls the XPCOM object referenced by the proxy with the given method. + * + * @param aProxy Proxy created by <code>createProxy</code> + * @param aMethodName name of method that we want to call + * @param aParams array of params passed to method + * + * @return return value as defined by given method + * + * @exception XPCOMException if XPCOM method failed. Values of XPCOMException + * are defined by the method called. + */ + protected static native Object callXPCOMMethod(Object aProxy, + String aMethodName, Object[] aParams); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java new file mode 100644 index 00000000..595a7a2c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java @@ -0,0 +1,53 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +package org.mozilla.xpcom.internal; + + +/** + * This interface forms the foundation of any XPCOMJavaProxy that is created. + * It allows us to handle any JVM calls to <code>finalize</code> when the Proxy + * is garbage collected. + */ +public interface XPCOMJavaProxyBase { + + /** + * @see java.lang.Object#finalize() + */ + void finalize() throws Throwable; + +} diff --git a/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java b/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java new file mode 100644 index 00000000..0a765fa0 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java @@ -0,0 +1,31 @@ +/* $Id: VBoxObjectBase.java $ */ +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ +import org.mozilla.interfaces.nsISupports; + +public abstract class VBoxObjectBase implements nsISupports +{ + public nsISupports queryInterface(String iid) + { + return org.mozilla.xpcom.Mozilla.queryInterface(this, iid); + } +} diff --git a/src/libs/xpcom18a4/java/tools/gen-nsError.pl b/src/libs/xpcom18a4/java/tools/gen-nsError.pl new file mode 100755 index 00000000..da866b83 --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/gen-nsError.pl @@ -0,0 +1,161 @@ +#! /usr/bin/env perl +# ***** 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 Java XPCOM Bindings. +# +# The Initial Developer of the Original Code is +# Michal Ceresna. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Michal Ceresna (ceresna@dbai.tuwien.ac.at) +# Javier Pedemonte (jhpedemonte@gmail.com) +# +# Alternatively, the contents of this file may be used under the terms of +# either 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 ***** + +# Generates XPCOMError.java from xpcom/base/nsError.h +# +# usage: perl gen-nsErrors.pl < <topsrcdir>/xpcom/base/nsError.h > XPCOMError.java + + +print "/* ***** BEGIN LICENSE BLOCK *****\n"; +print " * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n"; +print " *\n"; +print " * The contents of this file are subject to the Mozilla Public License Version\n"; +print " * 1.1 (the \"License\"); you may not use this file except in compliance with\n"; +print " * the License. You may obtain a copy of the License at\n"; +print " * http://www.mozilla.org/MPL/\n"; +print " *\n"; +print " * Software distributed under the License is distributed on an \"AS IS\" basis,\n"; +print " * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n"; +print " * for the specific language governing rights and limitations under the\n"; +print " * License.\n"; +print " *\n"; +print " * The Original Code is mozilla.org code.\n"; +print " *\n"; +print " * The Initial Developer of the Original Code is\n"; +print " * Netscape Communications Corporation.\n"; +print " * Portions created by the Initial Developer are Copyright (C) 1998\n"; +print " * the Initial Developer. All Rights Reserved.\n"; +print " *\n"; +print " * Contributor(s):\n"; +print " *\n"; +print " * Alternatively, the contents of this file may be used under the terms of\n"; +print " * either of the GNU General Public License Version 2 or later (the \"GPL\"),\n"; +print " * or the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\n"; +print " * in which case the provisions of the GPL or the LGPL are applicable instead\n"; +print " * of those above. If you wish to allow use of your version of this file only\n"; +print " * under the terms of either the GPL or the LGPL, and not to allow others to\n"; +print " * use your version of this file under the terms of the MPL, indicate your\n"; +print " * decision by deleting the provisions above and replace them with the notice\n"; +print " * and other provisions required by the GPL or the LGPL. If you do not delete\n"; +print " * the provisions above, a recipient may use your version of this file under\n"; +print " * the terms of any one of the MPL, the GPL or the LGPL.\n"; +print " *\n"; +print " * ***** END LICENSE BLOCK ***** */\n"; + +print "\n"; +print "package org.mozilla.xpcom;\n"; +print "\n\n"; + +print "/**\n"; +print " * Mozilla error codes.\n"; +print " *\n"; +print " * THIS FILE GENERATED FROM mozilla/xpcom/base/nsError.h.\n"; +print " * PLEASE SEE THAT FILE FOR FULL DOCUMENTATION.\n"; +print " */\n"; +print "public interface XPCOMError {\n"; + +while (<STDIN>) { + $line = $_; + + if ($prevline) { + $_ = $prevline.$_; + } + if (/(.*)\\$/) { + #splitted line + $prevline = $1; + next; + } + $prevline = ""; + + if (/^\s*#define\s+(NS_[A-Z_]+)\s+(0x)?([0-9a-fA-F]+)\s*$/) { + #define NS_ERROR_MODULE_XPCOM 1 + #define NS_ERROR_MODULE_BASE_OFFSET 0x45 + print " public static final long $1 = $2$3L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+\((NS_[A-Z_]+)\s+\+\s+(0x)?([0-9a-fA-F]+)\s*\)\s*/) { + #define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + #define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + print " public static final long $1 = $2 + $3$4L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+(NS_[A-Z_]+)\s\s*/) { + #define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + print " public static final long $1 = $2;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+\(\(nsresult\)\s*(0x)?([0-9a-fA-F]+)L?\)\s*$/) { + #define NS_ERROR_BASE ((nsresult) 0xC1F30000) + #define NS_ERROR_ABORT ((nsresult) 0x80004004L) + print " public static final long $1 = $2$3L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+NS_ERROR_GENERATE_FAILURE\s*\(\s*(NS_[A-Z_]+)\s*,\s*([0-9]+)\s*\)\s*$/) { + #define NS_BASE_STREAM_CLOSED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) + $module = $2; + $code = $3; + print " public static final long $1 = ((NS_ERROR_SEVERITY_ERROR<<31) | (($module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | $code);\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+NS_ERROR_GENERATE_SUCCESS\s*\(\s*(NS_[A-Z_]+)\s*,\s*([0-9]+)\s*\)\s*$/) { + #define NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 1) + $module = $2; + $code = $3; + print " public static final long $1 = ((NS_ERROR_SEVERITY_SUCCESS<<31) | (($module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | $code);\n"; + } + elsif (/^\s*\/\*(.*)\*\/\s*$/ && !/^\s*\/\*@[\{\}]\*\/\s*$/ && + !/^\s*\/\*\ -\*- Mode:/) { + #single line comment, but not + #/*@{*/, /*@}*/, + #/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + print " /*$1*/\n"; + } + elsif (/^\s*$/) { + #empty line, but write only the first + #line from a sequence of empty lines + if (!$wasEmpty) { + print "\n"; + } + $wasEmpty = 1; + next; + } + else { + next; + } + + $wasEmpty = 0; +} + +print "}\n"; + diff --git a/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp b/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp new file mode 100644 index 00000000..60648beb --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp @@ -0,0 +1,952 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 "nsXPCOM.h" +#include "nsString.h" +#include "nsILocalFile.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" +#include "nsCOMPtr.h" +#include "prmem.h" +#include "xptcall.h" +#ifdef VBOX +#include "nsFileStreams.h" +static nsresult +NS_NewLocalFileInputStream(nsIInputStream **aResult, + nsIFile *aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsFileInputStream* in = new nsFileInputStream(); + nsresult rv; + + rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_SUCCEEDED(rv)) + NS_ADDREF(*aResult = in); + + return rv; +} + +inline nsresult +NS_NewLocalFileOutputStream(nsIOutputStream **aResult, + nsIFile *aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsFileOutputStream* in = new nsFileOutputStream(); + nsresult rv; + + rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_SUCCEEDED(rv)) + NS_ADDREF(*aResult = in); + + return rv; +} + + +#else +#include "nsNetUtil.h" +#endif +#include "nsHashSets.h" +#include "nsIWeakReference.h" +#include <stdio.h> + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#define WRITE_NOSCRIPT_METHODS + + +class TypeInfo +{ +public: + static nsresult GetParentInfo(nsIInterfaceInfo* aIInfo, + nsIInterfaceInfo** aParentInfo, + PRUint16* aParentMethodCount, + PRUint16* aParentConstCount) + { + nsCOMPtr<nsIInterfaceInfo> parent; + nsresult rv = aIInfo->GetParent(getter_AddRefs(parent)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!parent) { + *aParentInfo = nsnull; + *aParentMethodCount = 0; + return NS_OK; + } + + rv = parent->GetMethodCount(aParentMethodCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = parent->GetConstantCount(aParentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + + *aParentInfo = parent; + NS_ADDREF(*aParentInfo); + return rv; + } + + static nsresult GetInterfaceName(nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, + const nsXPTParamInfo* aParamInfo, + char** aResult) + { + static const char isupp_str[] = "nsISupports"; + + nsIID* iid; + nsresult rv = aIInfo->GetIIDForParam(aMethodIndex, aParamInfo, &iid); + if (NS_FAILED(rv)) { + // GetIIDForParam will sometimes fail to find an interface, particularly + // if that interface is not defined in an IDL file. In those cases, just + // return |nsISupports|. + // + // For example, the |onStreamComplete| method for the interface + // |nsIUnicharStreamLoaderObserver| takes a param of + // |nsIUnicharInputStream|, which is defined in a simple header file, not + // an IDL file. + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + + } else { + + // In Javaconnect, we handle weak references internally; no need for the + // |nsIWeakReference| interface. So just return |nsISupports|. + if (iid->Equals(NS_GET_IID(nsIWeakReference))) { + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + + } else { + + // Some methods take parameters of non-scriptable interfaces. But we + // only output scriptable interfaces. So if one of the param types is + // a non-scriptable interface, output |nsISupports| instead of the + // interface name. + nsCOMPtr<nsIInterfaceInfo> info; + nsCOMPtr<nsIInterfaceInfoManager> iim = + getter_AddRefs(XPTI_GetInterfaceInfoManager()); + NS_ASSERTION(iim, "could not get interface info manager"); + rv = iim->GetInfoForIID(iid, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + PRBool scriptable; + if (NS_SUCCEEDED(rv)) { + info->IsScriptable(&scriptable); + } + if (NS_FAILED(rv) || !scriptable) { + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + } else { + + // If is scriptable, get name for given IID + rv = iim->GetNameForIID(iid, aResult); + } + } + + nsMemory::Free(iid); + } + + return rv; + } +}; + + +static const char* kJavaKeywords[] = { + "abstract", "default", "if" , "private" , "this" , + "boolean" , "do" , "implements", "protected" , "throw" , + "break" , "double" , "import", "public" , "throws" , + "byte" , "else" , "instanceof", "return" , "transient", + "case" , "extends", "int" , "short" , "try" , + "catch" , "final" , "interface" , "static" , "void" , + "char" , "finally", "long" , "strictfp" , "volatile" , + "class" , "float" , "native" , "super" , "while" , + "const" , "for" , "new" , "switch" , + "continue", "goto" , "package" , "synchronized", + "assert" , /* added in Java 1.4 */ + "enum" , /* added in Java 5.0 */ + "clone" , /* clone is a member function of java.lang.Object */ + "finalize" /* finalize is a member function of java.lang.Object */ +}; + +#ifdef WRITE_NOSCRIPT_METHODS +// SWT uses [noscript] methods of the following interfaces, so we need to +// output the [noscript] methods for these interfaces. +static const char* kNoscriptMethodIfaces[] = { + "nsIBaseWindow", "nsIEmbeddingSiteWindow" +}; +#endif + + +class Generate +{ + nsILocalFile* mOutputDir; + nsCStringHashSet mIfaceTable; + nsCStringHashSet mJavaKeywords; +#ifdef WRITE_NOSCRIPT_METHODS + nsCStringHashSet mNoscriptMethodsTable; +#endif + +public: + Generate(nsILocalFile* aOutputDir) + : mOutputDir(aOutputDir) + { + mIfaceTable.Init(100); + + PRUint32 size = NS_ARRAY_LENGTH(kJavaKeywords); + mJavaKeywords.Init(size); + for (PRUint32 i = 0; i < size; i++) { + mJavaKeywords.Put(nsDependentCString(kJavaKeywords[i])); + } + +#ifdef WRITE_NOSCRIPT_METHODS + size = NS_ARRAY_LENGTH(kNoscriptMethodIfaces); + mNoscriptMethodsTable.Init(size); + for (PRUint32 j = 0; j < size; j++) { + mNoscriptMethodsTable.Put(nsDependentCString(kNoscriptMethodIfaces[j])); + } +#endif + } + + ~Generate() + { + } + + nsresult GenerateInterfaces() + { + nsresult rv; + + nsCOMPtr<nsIInterfaceInfoManager> iim = + getter_AddRefs(XPTI_GetInterfaceInfoManager()); + NS_ASSERTION(iim, "could not get interface info manager"); + nsCOMPtr<nsIEnumerator> etor; + rv = iim->EnumerateInterfaces(getter_AddRefs(etor)); + NS_ENSURE_SUCCESS(rv, rv); + + // loop over interfaces + etor->First(); + do { + // get current interface + nsCOMPtr<nsISupports> item; + rv = etor->CurrentItem(getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIInterfaceInfo> iface(do_QueryInterface(item)); + if (!iface) + break; + + // we only care about scriptable interfaces, so skip over those + // that aren't + PRBool scriptable; + iface->IsScriptable(&scriptable); + if (!scriptable) { + // XXX SWT uses non-scriptable interface 'nsIAppShell' (bug 270892), so + // include that one. + const char* iface_name; + iface->GetNameShared(&iface_name); + if (strcmp("nsIAppShell", iface_name) != 0) + continue; + } + + rv = WriteOneInterface(iface); + NS_ENSURE_SUCCESS(rv, rv); + + } while (NS_SUCCEEDED(etor->Next())); + + return NS_OK; + } + + nsresult WriteOneInterface(nsIInterfaceInfo* aIInfo) + { + nsresult rv; + + // write each interface only once + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (mIfaceTable.Contains(nsDependentCString(iface_name))) + return NS_OK; + + // write any parent interface + nsCOMPtr<nsIInterfaceInfo> parentInfo; + PRUint16 parentMethodCount, parentConstCount; + rv = TypeInfo::GetParentInfo(aIInfo, getter_AddRefs(parentInfo), + &parentMethodCount, &parentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + if (parentInfo) + WriteOneInterface(parentInfo); + + mIfaceTable.Put(nsDependentCString(iface_name)); + + // create file for interface + nsCOMPtr<nsIOutputStream> out; + rv = OpenIfaceFileStream(iface_name, getter_AddRefs(out)); + NS_ENSURE_SUCCESS(rv, rv); + + // write contents to file + rv = WriteHeader(out, iface_name); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteInterfaceStart(out, aIInfo, parentInfo); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteIID(out, aIInfo); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteConstants(out, aIInfo, parentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteMethods(out, aIInfo, parentMethodCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteInterfaceEnd(out); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CloseIfaceFileStream(out); + + return rv; + } + + nsresult OpenIfaceFileStream(const char* aIfaceName, + nsIOutputStream** aResult) + { + nsresult rv; + + // create interface file in output dir + nsCOMPtr<nsIFile> iface_file; + rv = mOutputDir->Clone(getter_AddRefs(iface_file)); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoString filename; + filename.AppendASCII(aIfaceName); + filename.AppendLiteral(".java"); + rv = iface_file->Append(filename); + NS_ENSURE_SUCCESS(rv, rv); + + // create interface file + PRBool exists; + iface_file->Exists(&exists); + if (exists) + iface_file->Remove(PR_FALSE); + rv = iface_file->Create(nsIFile::NORMAL_FILE_TYPE, 0644); + NS_ENSURE_SUCCESS(rv, rv); + + // create output stream for writing to file + nsCOMPtr<nsIOutputStream> out; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(out), iface_file); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = out; + NS_ADDREF(*aResult); + return NS_OK; + } + + nsresult CloseIfaceFileStream(nsIOutputStream* out) + { + return out->Close(); + } + + nsresult WriteHeader(nsIOutputStream* out, const char* aIfaceName) + { + static const char kHeader1[] = + "/**\n" + " * NOTE: THIS IS A GENERATED FILE. PLEASE CONSULT THE ORIGINAL IDL FILE\n" + " * FOR THE FULL DOCUMENTION AND LICENSE.\n" + " *\n" + " * @see <a href=\"http://lxr.mozilla.org/mozilla/search?string="; + static const char kHeader2[]= "\">\n **/\n\n"; + static const char kPackage[] = "package org.mozilla.interfaces;\n\n"; + + PRUint32 count; + nsresult rv = out->Write(kHeader1, sizeof(kHeader1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString searchTerm; + searchTerm.AppendLiteral("interface+"); + searchTerm.AppendASCII(aIfaceName); + // LXR limits to 29 chars + rv = out->Write(searchTerm.get(), PR_MIN(29, searchTerm.Length()), &count); + NS_ENSURE_SUCCESS(rv, rv); + + rv = out->Write(kHeader2, sizeof(kHeader2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kPackage, sizeof(kPackage) - 1, &count); + return rv; + } + + nsresult WriteInterfaceStart(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + nsIInterfaceInfo* aParentInfo) + { + static const char kIfaceDecl1[] = "public interface "; + static const char kParentDecl[] = " extends "; + static const char kIfaceDecl2[] = "\n{\n"; + + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + PRUint32 count; + nsresult rv = out->Write(kIfaceDecl1, sizeof(kIfaceDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iface_name, strlen(iface_name), &count); + NS_ENSURE_SUCCESS(rv, rv); + + if (aParentInfo) { + const char* parent_name; + aParentInfo->GetNameShared(&parent_name); + rv = out->Write(kParentDecl, sizeof(kParentDecl) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(parent_name, strlen(parent_name), &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = out->Write(kIfaceDecl2, sizeof(kIfaceDecl2) - 1, &count); + return rv; + } + + nsresult WriteInterfaceEnd(nsIOutputStream* out) + { + PRUint32 count; + return out->Write("}\n", 2, &count); + } + + nsresult WriteIID(nsIOutputStream* out, nsIInterfaceInfo* aIInfo) + { + static const char kIIDDecl1[] = " public static final String "; + static const char kIIDDecl2[] = " =\n \""; + static const char kIIDDecl3[] = "\";\n\n"; + + nsIID* iid = nsnull; + aIInfo->GetInterfaceIID(&iid); + if (!iid) + return NS_ERROR_OUT_OF_MEMORY; + + // create iid field name + nsCAutoString iid_name; + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (strncmp("ns", iface_name, 2) == 0) { + iid_name.AppendLiteral("NS_"); + iid_name.Append(iface_name + 2); + } else { + iid_name.Append(iface_name); + } + iid_name.AppendLiteral("_IID"); + ToUpperCase(iid_name); + + // get iid string + char* iid_str = iid->ToString(); + if (!iid_str) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 count; + nsresult rv = out->Write(kIIDDecl1, sizeof(kIIDDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iid_name.get(), iid_name.Length(), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kIIDDecl2, sizeof(kIIDDecl2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iid_str, strlen(iid_str), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kIIDDecl3, sizeof(kIIDDecl3) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // cleanup + PR_Free(iid_str); + nsMemory::Free(iid); + return NS_OK; + } + + nsresult WriteConstants(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aParentConstCount) + { + static const char kConstDecl1[] = " public static final "; + static const char kConstDecl2[] = " = "; + static const char kConstDecl3[] = ";\n\n"; + + PRUint16 constCount; + nsresult rv = aIInfo->GetConstantCount(&constCount); + NS_ENSURE_SUCCESS(rv, rv); + + for (PRUint16 i = aParentConstCount; i < constCount; i++) { + const nsXPTConstant* constInfo; + rv = aIInfo->GetConstant(i, &constInfo); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 count; + rv = out->Write(kConstDecl1, sizeof(kConstDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + const nsXPTType &type = constInfo->GetType(); + rv = WriteType(out, &type, aIInfo, nsnull, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(" ", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + const char* name = constInfo->GetName(); + rv = out->Write(name, strlen(name), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kConstDecl2, sizeof(kConstDecl2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + rv = WriteConstantValue(out, &type, constInfo->GetValue()); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kConstDecl3, sizeof(kConstDecl3) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + nsresult WriteConstantValue(nsIOutputStream* out, const nsXPTType* aType, + const nsXPTCMiniVariant* aValue) + { + char buf[32]; + switch (aType->TagPart()) { + case nsXPTType::T_I8: + snprintf(buf, sizeof(buf), "%d", aValue->val.i8); + break; + + case nsXPTType::T_U8: + snprintf(buf, sizeof(buf), "%u", aValue->val.u8); + break; + + case nsXPTType::T_I16: + snprintf(buf, sizeof(buf), "%d", aValue->val.i16); + break; + + case nsXPTType::T_U16: + snprintf(buf, sizeof(buf), "%u", aValue->val.u16); + break; + + case nsXPTType::T_I32: + snprintf(buf, sizeof(buf), "%d", aValue->val.i32); + break; + + case nsXPTType::T_U32: + snprintf(buf, sizeof(buf), "%uL", aValue->val.u32); + break; + + case nsXPTType::T_I64: + snprintf(buf, sizeof(buf), "%lldL", aValue->val.i64); + break; + + case nsXPTType::T_U64: + snprintf(buf, sizeof(buf), "%lluL", aValue->val.u64); + break; + + case nsXPTType::T_FLOAT: + snprintf(buf, sizeof(buf), "%f", aValue->val.f); + break; + + case nsXPTType::T_DOUBLE: + snprintf(buf, sizeof(buf), "%f", aValue->val.d); + break; + + case nsXPTType::T_BOOL: + if (aValue->val.b) + sprintf(buf, "true"); + else + sprintf(buf, "false"); + break; + + case nsXPTType::T_CHAR: + snprintf(buf, sizeof(buf), "%c", aValue->val.c); + break; + + case nsXPTType::T_WCHAR: + snprintf(buf, sizeof(buf), "%c", aValue->val.wc); + break; + + default: + NS_WARNING("unexpected constant type"); + return NS_ERROR_UNEXPECTED; + } + + PRUint32 count; + return out->Write(buf, strlen(buf), &count); + } + + nsresult WriteMethods(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aParentMethodCount) + { + PRUint16 methodCount; + nsresult rv = aIInfo->GetMethodCount(&methodCount); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef DEBUG_bird /* attributes first, then method. For making diffing easier. */ + for (int pass = 0; pass < 2; pass++) +#endif + for (PRUint16 i = aParentMethodCount; i < methodCount; i++) { + const nsXPTMethodInfo* methodInfo; + rv = aIInfo->GetMethodInfo(i, &methodInfo); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef WRITE_NOSCRIPT_METHODS + // XXX + // SWT makes use of [noscript] methods in some classes, so output them + // for those classes. + + // skip [notxpcom] methods + if (methodInfo->IsNotXPCOM()) + continue; + + // skip most hidden ([noscript]) methods + if (methodInfo->IsHidden()) { + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (!mNoscriptMethodsTable.Contains(nsDependentCString(iface_name))) + continue; + } +#else + // skip hidden ([noscript]) or [notxpcom] methods + if (methodInfo->IsHidden() || methodInfo->IsNotXPCOM()) + continue; +#endif +#ifdef DEBUG_bird /* attributes first, then method. For making diffing easier. */ + if ((methodInfo->IsSetter() || methodInfo->IsGetter()) == pass) + continue; +#endif + + rv = WriteOneMethod(out, aIInfo, methodInfo, i); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + nsresult WriteOneMethod(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex) + { + static const char kMethodDecl1[] = " public "; + static const char kVoidReturn[] = "void"; + static const char kParamSeparator[] = ", "; + static const char kMethodDecl2[] = ");\n\n"; + + PRUint32 count; + nsresult rv = out->Write(kMethodDecl1, sizeof(kMethodDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // write return type + PRUint8 paramCount = aMethodInfo->GetParamCount(); + const nsXPTParamInfo* resultInfo = nsnull; + for (PRUint8 i = 0; i < paramCount; i++) { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(i); + if (paramInfo.IsRetval()) { + resultInfo = ¶mInfo; + break; + } + } + if (resultInfo) { + rv = WriteParam(out, aIInfo, aMethodIndex, resultInfo, 0); + } else { + rv = out->Write(kVoidReturn, sizeof(kVoidReturn) - 1, &count); + } + NS_ENSURE_SUCCESS(rv, rv); + + // write method name string + nsCAutoString method_name; + const char* name = aMethodInfo->GetName(); + if (aMethodInfo->IsGetter() || aMethodInfo->IsSetter()) { + if (aMethodInfo->IsGetter()) + method_name.AppendLiteral("get"); + else + method_name.AppendLiteral("set"); + method_name.Append(toupper(name[0])); + method_name.AppendASCII(name + 1); + } else { + method_name.Append(tolower(name[0])); + method_name.AppendASCII(name + 1); + // don't use Java keywords as method names + if (mJavaKeywords.Contains(method_name)) + method_name.Append('_'); + } + rv = out->Write(" ", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(method_name.get(), method_name.Length(), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write("(", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // write parameters + for (PRUint8 j = 0; j < paramCount; j++) { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(j); + if (paramInfo.IsRetval()) + continue; + + if (j != 0) { + rv = out->Write(kParamSeparator, sizeof(kParamSeparator) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = WriteParam(out, aIInfo, aMethodIndex, ¶mInfo, j + 1); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = out->Write(kMethodDecl2, sizeof(kMethodDecl2) - 1, &count); + return rv; + } + + nsresult WriteParam(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, const nsXPTParamInfo* aParamInfo, + PRUint8 aIndex) + { + const nsXPTType &type = aParamInfo->GetType(); + nsresult rv = WriteType(out, &type, aIInfo, aMethodIndex, aParamInfo); + NS_ENSURE_SUCCESS(rv, rv); + + // if parameter is 'out' or 'inout', make it a Java array + PRUint32 count; + if (aParamInfo->IsOut() && !aParamInfo->IsRetval()) { + rv = out->Write("[]", 2, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + // write name for parameter (but not for 'retval' param) + if (aIndex) { + char buf[10]; + snprintf(buf, sizeof(buf), " arg%d", aIndex); + rv = out->Write(buf, strlen(buf), &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + /** + * Write out the Java type for the given XPIDL type. + * + * NOTE: Java doesn't support unsigned types. So for any unsigned XPIDL type, + * we move up to the next largest Java type. This way we ensure that we don't + * lose any info. + */ + nsresult WriteType(nsIOutputStream* out, const nsXPTType* aType, + nsIInterfaceInfo* aIInfo, PRUint16 aMethodIndex, + const nsXPTParamInfo* aParamInfo) + { + nsresult rv; + PRUint32 count; + switch (aType->TagPart()) { + case nsXPTType::T_I8: + rv = out->Write("byte", 4, &count); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + rv = out->Write("short", 5, &count); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + rv = out->Write("int", 3, &count); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + rv = out->Write("long", 4, &count); + break; + + case nsXPTType::T_FLOAT: + rv = out->Write("float", 5, &count); + break; + + // XXX how should we handle 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + rv = out->Write("double", 6, &count); + break; + + case nsXPTType::T_BOOL: + rv = out->Write("boolean", 7, &count); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + rv = out->Write("char", 4, &count); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + rv = out->Write("String", 6, &count); + break; + + case nsXPTType::T_INTERFACE: + { + char* iface_name = nsnull; + rv = TypeInfo::GetInterfaceName(aIInfo, aMethodIndex, aParamInfo, + &iface_name); + if (NS_FAILED(rv) || !iface_name) { + rv = NS_ERROR_FAILURE; + break; + } + + rv = out->Write(iface_name, strlen(iface_name), &count); + nsMemory::Free(iface_name); + break; + } + + case nsXPTType::T_INTERFACE_IS: + rv = out->Write("nsISupports", 11, &count); + break; + + case nsXPTType::T_VOID: + rv = out->Write("int", 3, &count); + break; + + case nsXPTType::T_ARRAY: + { + // get array type + nsXPTType xpttype; + rv = aIInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &xpttype); + if (NS_FAILED(rv)) + break; + + rv = WriteType(out, &xpttype, aIInfo, aMethodIndex, aParamInfo); + if (NS_FAILED(rv)) + break; + + rv = out->Write("[]", 2, &count); + break; + } + + default: + fprintf(stderr, "WARNING: unexpected parameter type %d\n", + aType->TagPart()); + return NS_ERROR_UNEXPECTED; + } + + return rv; + } +}; + +void PrintUsage(char** argv) +{ + static const char usage_str[] = + "Usage: %s -d path\n" + " -d output directory for Java interface files\n"; + fprintf(stderr, usage_str, argv[0]); +} +#ifdef VBOX +#include <VBox/com/com.h> +using namespace com; + +#include <iprt/initterm.h> +#include <iprt/string.h> +#include <iprt/alloca.h> +#include <iprt/stream.h> +#endif + +int main(int argc, char** argv) +{ + nsresult rv = NS_OK; + nsCOMPtr<nsILocalFile> output_dir; + +#ifdef VBOX +#if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rv = RTR3InitExe(argc, &argv, 0); +#else + const char *pszHome = getenv("VBOX_PROGRAM_PATH"); + if (pszHome) { + size_t cchHome = strlen(pszHome); + char *pszExePath = (char *)alloca(cchHome + 32); + memcpy(pszExePath, pszHome, cchHome); + memcpy(pszExePath + cchHome, "/pythonfake", sizeof("/pythonfake")); + rc = RTR3InitEx(RTR3INIT_VER_CUR, 0, argc, &argv, pszExePath); + } else { + rv = RTR3InitExe(argc, &argv, 0); + } +#endif +#endif + + // handle command line arguments + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + rv = NS_ERROR_FAILURE; + break; + } + + switch (argv[i][1]) { + case 'd': { + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing output directory after -d\n"); + rv = NS_ERROR_FAILURE; + break; + } + + // see if given path exists + rv = NS_NewNativeLocalFile(nsDependentCString(argv[++i]), PR_TRUE, + getter_AddRefs(output_dir)); + PRBool val; + if (NS_FAILED(rv) || NS_FAILED(output_dir->Exists(&val)) || !val || + NS_FAILED(output_dir->IsDirectory(&val)) || !val) + { + fprintf(stderr, + "ERROR: output directory doesn't exist / isn't a directory\n"); + rv = NS_ERROR_FAILURE; + break; + } + + break; + } + + default: { + fprintf(stderr, "ERROR: unknown option %s\n", argv[i]); + rv = NS_ERROR_FAILURE; + break; + } + } + } + + if (NS_FAILED(rv)) { + PrintUsage(argv); + return 1; + } + +#ifdef VBOX + rv = com::Initialize(); +#else + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif + NS_ENSURE_SUCCESS(rv, rv); + + Generate gen(output_dir); + rv = gen.GenerateInterfaces(); + +#ifdef VBOX + // very short-living XPCOM processes trigger problem on shutdown - ignoring it not a big deal anyway + //com::Shutdown(); +#else + NS_ShutdownXPCOM(nsnull); +#endif + return rv; +} diff --git a/src/libs/xpcom18a4/java/tools/genjifaces.xsl b/src/libs/xpcom18a4/java/tools/genjifaces.xsl new file mode 100644 index 00000000..05455a4d --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/genjifaces.xsl @@ -0,0 +1,600 @@ +<xsl:stylesheet version = '1.0' + xmlns:xsl='http://www.w3.org/1999/XSL/Transform' + xmlns:vbox="http://www.virtualbox.org/" + xmlns:exsl="http://exslt.org/common" + extension-element-prefixes="exsl"> + +<!-- + genjifaces.xsl: + XSLT stylesheet that generates Java XPCOM bridge interface code from VirtualBox.xidl. +--> +<!-- + Copyright (C) 2010-2022 Oracle and/or its affiliates. + + This file is part of VirtualBox base platform packages, as + available from https://www.virtualbox.org. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, in version 3 of the + License. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <https://www.gnu.org/licenses>. + + SPDX-License-Identifier: GPL-3.0-only +--> + +<xsl:output + method="text" + version="1.0" + encoding="utf-8" + indent="no"/> + +<!-- - - - - - - - - - - - - - - - - - - - - - - + global XSLT variables + - - - - - - - - - - - - - - - - - - - - - - --> + +<xsl:variable name="G_xsltFilename" select="'genjifaces.xsl'" /> + + +<!-- - - - - - - - - - - - - - - - - - - - - - - + Keys for more efficiently looking up of types. +- - - - - - - - - - - - - - - - - - - - - - --> +<xsl:key name="G_keyEnumsByName" match="//enum[@name]" use="@name"/> +<xsl:key name="G_keyInterfacesByName" match="//interface[@name]" use="@name"/> + +<!-- + xsltprocNewlineOutputHack - emits a single new line. + + Hack Alert! This template helps xsltproc split up the output text elements + and avoid reallocating them into the MB range. Calls to this + template is made occationally while generating larger output + file. It's not necessary for small stuff like header. + + The trick we're playing on xsltproc has to do with CDATA + and/or the escape setting of the xsl:text element. It forces + xsltproc to allocate a new output element, thus preventing + things from growing out of proportions and slowing us down. + + This was successfully employed to reduce a 18+ seconds run to + around one second (possibly less due to kmk overhead). + --> +<xsl:template name="xsltprocNewlineOutputHack"> + <xsl:text disable-output-escaping="yes"><![CDATA[ +]]></xsl:text> +</xsl:template> + +<xsl:template name="uppercase"> + <xsl:param name="str" select="."/> + <xsl:value-of select="translate($str, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" /> +</xsl:template> + +<xsl:template name="capitalize"> + <xsl:param name="str" select="."/> + <xsl:value-of select=" + concat(translate(substring($str,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'), + substring($str,2))"/> +</xsl:template> + +<xsl:template name="makeGetterName"> + <xsl:param name="attrname" /> + <xsl:variable name="capsname"> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="$attrname" /> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="concat('get', $capsname)" /> +</xsl:template> + +<xsl:template name="makeSetterName"> + <xsl:param name="attrname" /> + <xsl:variable name="capsname"> + <xsl:call-template name="capitalize"> + <xsl:with-param name="str" select="$attrname" /> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="concat('set', $capsname)" /> +</xsl:template> + +<xsl:template name="fileheader"> + <xsl:param name="name" /> + <xsl:text>/** @file +</xsl:text> + <xsl:value-of select="concat(' * ',$name)"/> +<xsl:text> + * + * DO NOT EDIT! This is a generated file. + * Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML) + * Generator: src/VBox/src/libs/xpcom18a4/java/tools/genjifaces.xsl + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ +</xsl:text> +</xsl:template> + +<xsl:template name="startFile"> + <xsl:param name="file" /> + + <xsl:value-of select="concat(' // ##### BEGINFILE "', $file, '" ')" /> + <xsl:call-template name="fileheader"> + <xsl:with-param name="name" select="$file" /> + </xsl:call-template> + + <xsl:value-of select=" 'package org.mozilla.interfaces; '" /> +</xsl:template> + +<xsl:template name="endFile"> + <xsl:param name="file" /> + <xsl:value-of select="concat(' // ##### ENDFILE "', $file, '" ')" /> + <xsl:call-template name="xsltprocNewlineOutputHack"/> +</xsl:template> + + +<xsl:template name="emitHandwritten"> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsISupports.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsISupports +{ + public static final String NS_ISUPPORTS_IID = + "{00000000-0000-0000-c000-000000000046}"; + + public nsISupports queryInterface(String arg1); +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsISupports.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIComponentManager.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIComponentManager extends nsISupports +{ + public static final String NS_ICOMPONENTMANAGER_IID = + "{a88e5a60-205a-4bb1-94e1-2628daf51eae}"; + + public nsISupports getClassObject(String arg1, String arg2); + + public nsISupports getClassObjectByContractID(String arg1, String arg2); + + public nsISupports createInstance(String arg1, nsISupports arg2, String arg3); + + public nsISupports createInstanceByContractID(String arg1, nsISupports arg2, String arg3); +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsIComponentManager.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIServiceManager.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIServiceManager extends nsISupports +{ + public static final String NS_ISERVICEMANAGER_IID = + "{8bb35ed9-e332-462d-9155-4a002ab5c958}"; + + public nsISupports getService(String arg1, String arg2); + + public nsISupports getServiceByContractID(String arg1, String arg2); + + public boolean isServiceInstantiated(String arg1, String arg2); + + public boolean isServiceInstantiatedByContractID(String arg1, String arg2); +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsIServiceManager.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIExceptionManager.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIExceptionManager extends nsISupports +{ + public static final String NS_IEXCEPTIONMANAGER_IID = + "{efc9d00b-231c-4feb-852c-ac017266a415}"; + + public nsIException getCurrentException(); +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsISupports.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIExceptionService.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIExceptionService extends nsIExceptionManager +{ + public static final String NS_IEXCEPTIONSERVICE_IID = + "{35a88f54-f267-4414-92a7-191f6454ab52}"; + + public nsIExceptionManager getCurrentExceptionManager(); +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsISupports.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIException.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIException extends nsISupports +{ + public static final String NS_IEXCEPTION_IID = + "{f3a8d3b4-c424-4edc-8bf6-8974c983ba78}"; + + // No methods - placeholder +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsISupports.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIComponentRegistrar.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIComponentRegistrar extends nsISupports +{ + public static final String NS_ICOMPONENTREGISTRAR_IID = + "{2417cbfe-65ad-48a6-b4b6-eb84db174392}"; + + // No methods - placeholder +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsIComponentRegistrar.java'" /> + </xsl:call-template> + + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsIFile.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsIFile extends nsISupports +{ + public static final String NS_IFILE_IID = + "{c8c0a080-0868-11d3-915f-d9d889d48e3c}"; + + // No methods - placeholder +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsIFile.java'" /> + </xsl:call-template> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="'nsILocalFile.java'" /> + </xsl:call-template> + + <xsl:text><![CDATA[ +public interface nsILocalFile extends nsIFile +{ + public static final String NS_ILOCALFILE_IID = + "{aa610f20-a889-11d3-8c81-000064657374}"; + + // No methods - placeholder +} +]]></xsl:text> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="'nsILocalFile.java'" /> + </xsl:call-template> + +</xsl:template> + +<xsl:template name="genEnum"> + <xsl:param name="enumname" /> + <xsl:param name="filename" /> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="$filename" /> + </xsl:call-template> + + <xsl:value-of select="concat('public interface ', $enumname, ' { ')" /> + + <xsl:variable name="uppername"> + <xsl:call-template name="uppercase"> + <xsl:with-param name="str" select="$enumname" /> + </xsl:call-template> + </xsl:variable> + + <xsl:value-of select="concat(' public static final String ', $uppername, '_IID = ', + ' "{',@uuid, '}"; ')" /> + + <xsl:for-each select="const"> + <xsl:variable name="enumconst" select="@name" /> + <xsl:value-of select="concat(' public static final long ', @name, ' = ', @value, 'L; ')" /> + </xsl:for-each> + + <xsl:value-of select="'} '" /> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="$filename" /> + </xsl:call-template> + +</xsl:template> + +<xsl:template name="typeIdl2Back"> + <xsl:param name="type" /> + <xsl:param name="safearray" /> + <xsl:param name="forceelem" /> + + <xsl:variable name="needarray" select="($safearray='yes') and not($forceelem='yes')" /> + + <xsl:choose> + <xsl:when test="$type='unsigned long long'"> + <!-- stupid, rewrite the bridge --> + <xsl:value-of select="'double'" /> + </xsl:when> + + <xsl:when test="$type='long long'"> + <xsl:value-of select="'long'" /> + </xsl:when> + + <xsl:when test="$type='unsigned long'"> + <xsl:value-of select="'long'" /> + </xsl:when> + + <xsl:when test="$type='long'"> + <xsl:value-of select="'int'" /> + </xsl:when> + + <xsl:when test="$type='unsigned short'"> + <xsl:value-of select="'int'" /> + </xsl:when> + + <xsl:when test="$type='short'"> + <xsl:value-of select="'short'" /> + </xsl:when> + + <xsl:when test="$type='octet'"> + <xsl:value-of select="'byte'" /> + </xsl:when> + + <xsl:when test="$type='boolean'"> + <xsl:value-of select="'boolean'" /> + </xsl:when> + + <xsl:when test="$type='$unknown'"> + <xsl:value-of select="'nsISupports'"/> + </xsl:when> + + <xsl:when test="$type='wstring'"> + <xsl:value-of select="'String'" /> + </xsl:when> + + <xsl:when test="$type='uuid'"> + <xsl:value-of select="'String'" /> + </xsl:when> + + <xsl:when test="count(key('G_keyInterfacesByName', $type)) > 0"> + <xsl:value-of select="$type" /> + </xsl:when> + + <xsl:when test="count(key('G_keyEnumsByName', $type)) > 0"> + <xsl:value-of select="'long'" /> + </xsl:when> + + </xsl:choose> + + <xsl:if test="$needarray"> + <xsl:value-of select="'[]'" /> + </xsl:if> + +</xsl:template> + +<xsl:template name="genIface"> + <xsl:param name="ifname" /> + <xsl:param name="filename" /> + + <xsl:call-template name="startFile"> + <xsl:with-param name="file" select="$filename" /> + </xsl:call-template> + + <xsl:variable name="extendsidl" select="key('G_keyInterfacesByName', $ifname)/@extends" /> + + <xsl:variable name="extends"> + <xsl:choose> + <xsl:when test="($extendsidl = '$unknown') or ($extendsidl = '$dispatched') or ($extendsidl = '$errorinfo')"> + <xsl:value-of select="'nsISupports'" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$extendsidl" /> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:value-of select="concat('public interface ', $ifname, ' extends ', $extends, ' { ')" /> + + <xsl:variable name="uppername"> + <xsl:call-template name="uppercase"> + <xsl:with-param name="str" select="$ifname" /> + </xsl:call-template> + </xsl:variable> + + <xsl:value-of select="concat(' public static final String ', $uppername, '_IID = ', + ' "{',@uuid, '}"; ')" /> + + <xsl:for-each select="attribute"> + <xsl:variable name="attrname" select="@name" /> + <xsl:variable name="attrtype" select="@type" /> + + <xsl:variable name="gettername"> + <xsl:call-template name="makeGetterName"> + <xsl:with-param name="attrname" select="$attrname" /> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="backtype"> + <xsl:call-template name="typeIdl2Back"> + <xsl:with-param name="type" select="$attrtype" /> + <xsl:with-param name="safearray" select="@safearray" /> + </xsl:call-template> + </xsl:variable> + + <xsl:variable name="callparam"> + <xsl:if test="@safearray='yes'"> + <xsl:value-of select="concat(' long[] ', @name, 'Size')" /> + </xsl:if> + </xsl:variable> + + <xsl:value-of select="concat(' public ', $backtype, ' ', $gettername, '(',$callparam,'); ')" /> + + <xsl:if test="not(@readonly='yes')"> + <xsl:variable name="settername"> + <xsl:call-template name="makeSetterName"> + <xsl:with-param name="attrname" select="$attrname" /> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="concat(' public void ', $settername, '(', $backtype, ' arg1); ')" /> + </xsl:if> + + </xsl:for-each> + + <xsl:for-each select="method"> + <xsl:variable name="methodname" select="@name" /> + <xsl:variable name="returnidltype" select="param[@dir='return']/@type" /> + <xsl:variable name="returnidlsafearray" select="param[@dir='return']/@safearray" /> + + <xsl:variable name="returntype"> + <xsl:choose> + <xsl:when test="$returnidltype"> + <xsl:call-template name="typeIdl2Back"> + <xsl:with-param name="type" select="$returnidltype" /> + <xsl:with-param name="safearray" select="$returnidlsafearray" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:text>void</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:value-of select="concat(' public ', $returntype, ' ', $methodname, '(')" /> + <xsl:for-each select="param"> + <xsl:variable name="paramtype"> + <xsl:call-template name="typeIdl2Back"> + <xsl:with-param name="type" select="@type" /> + <xsl:with-param name="safearray" select="@safearray" /> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="(@safearray='yes') and (@dir='return')"> + <xsl:value-of select="concat('long[] ', @name)" /> + </xsl:when> + <xsl:when test="(@safearray='yes') and (@dir='out')"> + <xsl:value-of select="concat('long[] ', @name, 'Size, ', $paramtype, '[] ', @name)" /> + </xsl:when> + <xsl:when test="(@safearray='yes') and (@dir='in') and (@type='octet')"> + <xsl:value-of select="concat($paramtype, ' ', @name)" /> + </xsl:when> + <xsl:when test="(@safearray='yes') and (@dir='in')"> + <xsl:value-of select="concat('long ', @name, 'Size, ', $paramtype, ' ', @name)" /> + </xsl:when> + <xsl:when test="@dir='out'"> + <xsl:value-of select="concat($paramtype, '[] ', @name)" /> + </xsl:when> + <xsl:when test="@dir='in'"> + <xsl:value-of select="concat($paramtype, ' ', @name)" /> + </xsl:when> + </xsl:choose> + <xsl:if test="not(position()=last()) and not(following-sibling::param[1]/@dir='return' and not(following-sibling::param[1]/@safearray='yes'))"> + <xsl:value-of select="', '" /> + </xsl:if> + </xsl:for-each> + <xsl:value-of select=" '); '" /> + + </xsl:for-each> + + <xsl:value-of select="'} '" /> + + <xsl:call-template name="endFile"> + <xsl:with-param name="file" select="$filename" /> + </xsl:call-template> + +</xsl:template> + + +<xsl:template match="/"> + + <!-- Handwritten files --> + <xsl:call-template name="emitHandwritten"/> + + <!-- Enums --> + <xsl:for-each select="//enum"> + <xsl:call-template name="genEnum"> + <xsl:with-param name="enumname" select="@name" /> + <xsl:with-param name="filename" select="concat(@name, '.java')" /> + </xsl:call-template> + </xsl:for-each> + + <!-- Interfaces --> + <xsl:for-each select="//interface"> + <xsl:variable name="self_target" select="current()/ancestor::if/@target"/> + <xsl:variable name="module" select="current()/ancestor::module/@name"/> + + <!-- We don't need WSDL-specific nor MIDL-specific interfaces here --> + <xsl:if test="not($self_target='wsdl') and not($self_target='midl') and not($module)"> + <xsl:call-template name="genIface"> + <xsl:with-param name="ifname" select="@name" /> + <xsl:with-param name="filename" select="concat(@name, '.java')" /> + </xsl:call-template> + </xsl:if> + + </xsl:for-each> + +</xsl:template> + +</xsl:stylesheet> |