/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    getMechanismsNative
 * Signature: (JJJJ)[Lorg/opensc/pkcs11/wrap/PKCS11Mechanism;
 */
jobjectArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_getAllowedMechanismsNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jlong ohandle)
{
  int rv;
  CK_ATTRIBUTE templ;
  CK_MECHANISM_TYPE_PTR mechanisms;
  CK_ULONG n_mechanisms;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  templ.type = CKA_ALLOWED_MECHANISMS;
  templ.pValue = NULL;
  templ.ulValueLen = 0;
      
  rv = mod->method->C_GetAttributeValue(hsession,ohandle,&templ,1);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetAttributeValue failed for attribute CKA_ALLOWED_MECHANISMS.");
      return 0;
    }

  if (templ.ulValueLen == ~((CK_ULONG)0))
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_FUNCTION_FAILED,
                          "C_GetAttributeValue returned ulValueLen -1 for attribute CKA_ALLOWED_MECHANISMS but returned CKR_OK. The underlying PKCS#11 module seems to be broken.");
      return 0;
    }

  templ.pValue = alloca(templ.ulValueLen);

  rv = mod->method->C_GetAttributeValue(hsession,ohandle,&templ,1);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetAttributeValue failed for attribute CKA_ALLOWED_MECHANISMS.");
      return 0;
    }

  if (templ.ulValueLen == ~((CK_ULONG)0))
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_FUNCTION_FAILED,
                          "C_GetAttributeValue returned ulValueLen -1 for attribute CKA_ALLOWED_MECHANISMS but returned CKR_OK. The underlying PKCS#11 module seems to be broken.");
      return 0;
    }

  mechanisms = (CK_MECHANISM_TYPE_PTR)templ.pValue;
  n_mechanisms = templ.ulValueLen/sizeof(CK_MECHANISM_TYPE);

  return pkcs11_slot_make_jmechanisms(env,mod,slot,mechanisms,n_mechanisms);
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    getMechanismsNative
 * Signature: (JJ)[Lorg/opensc/pkcs11/wrap/PKCS11Mechanism;
 */
jobjectArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_getMechanismsNative)
  (JNIEnv *env, jobject jslot, jlong mh, jlong handle)
{
  int rv;
  CK_ULONG n_mechanisms = 0;
  CK_MECHANISM_TYPE_PTR mechanisms;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,handle);
  if (!slot) return 0;

  rv = mod->method->C_GetMechanismList(slot->id,NULL,&n_mechanisms);

  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetMechanismList for PKCS11 slot %d failed.",
                          (int)slot->id);
      return 0;
    }

  mechanisms =
    (CK_MECHANISM_TYPE_PTR)alloca(n_mechanisms*sizeof(CK_MECHANISM_TYPE));

  rv = mod->method->C_GetMechanismList(slot->id,mechanisms,&n_mechanisms);

  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetMechanismList for PKCS11 slot %d failed.",
                          (int)slot->id);
      return 0;
    }

  return pkcs11_slot_make_jmechanisms(env,mod,slot,mechanisms,n_mechanisms);
}