summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp1711
1 files changed, 1711 insertions, 0 deletions
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 &paramInfo = aMethodInfo->params[i];
+ if (!paramInfo.IsRetval()) {
+ rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
+ aParams[i], java_params[i], methodSig);
+ } else {
+ retvalInfo = &paramInfo;
+ }
+ }
+ 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 &paramInfo = 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;
+}