static nsresult
SetupParam(const nsXPTParamInfo &p, nsXPTCVariant &v)
{
  const nsXPTType &t = p.GetType();

  if (p.IsIn() && p.IsDipper())
  {
    v.ptr = nsnull;

    switch (t.TagPart())
    {
      case nsXPTType::T_ASTRING:
      case nsXPTType::T_DOMSTRING:
        v.ptr = new nsString();
        if (!v.ptr)
          return NS_ERROR_OUT_OF_MEMORY;
        v.val.p = v.ptr;
        v.type = t;
        v.flags = nsXPTCVariant::PTR_IS_DATA | nsXPTCVariant::VAL_IS_DOMSTR;
        break;

      case nsXPTType::T_UTF8STRING:
      case nsXPTType::T_CSTRING:
        v.ptr = new nsCString();
        if (!v.ptr)
          return NS_ERROR_OUT_OF_MEMORY;
        v.val.p = v.ptr;
        v.type = t;
        v.flags = nsXPTCVariant::PTR_IS_DATA | nsXPTCVariant::VAL_IS_CSTR;
        break;

      default:
        LOG(("unhandled dipper: type=%d\n", t.TagPart()));
        return NS_ERROR_UNEXPECTED;
    }
  }
  else if (p.IsOut())
  {
    v.ptr = &v.val;
    v.type = t;
    v.flags = nsXPTCVariant::PTR_IS_DATA;
  }

  return NS_OK;
}
Exemplo n.º 2
0
/**
 * 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;
}
Exemplo n.º 3
0
/**
 * 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;
}