/*
   * Function: setFileCon
   * Purpose:  set the security context of a file object
   * Parameters:
   *       path: the location of the file system object
   *       con: the new security context of the file system object
   * Returns: true on success, false on error
   * Exception: NullPointerException is thrown if either path or context strign are NULL
   */
  static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
#ifdef HAVE_SELINUX
    if (isSELinuxDisabled)
      return false;

    if (path == NULL) {
      throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
      return false;
    }

    if (con == NULL) {
      throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
      return false;
    }

    const char *objectPath = env->GetStringUTFChars(path, NULL);
    const char *constant_con = env->GetStringUTFChars(con, NULL);

    // GetStringUTFChars returns const char * yet setfilecon needs char *
    char *newCon = const_cast<char *>(constant_con);

    int ret;
    if ((ret = setfilecon(objectPath, newCon)) == -1)
      goto bail;

    ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);

  bail:
    env->ReleaseStringUTFChars(path, objectPath);
    env->ReleaseStringUTFChars(con, constant_con);
    return (ret == 0) ? true : false;
#else
    return false;
#endif
  }
JNIEXPORT void JNICALL Java_jp_marisa_KeysetNative_push_1back__Ljp_marisa_KeyNative_2B(JNIEnv *env, jobject pthis, jobject key, jbyte end_marker) {
	marisa::Keyset* native_keyset = ensure_create_keyset(env, pthis);
	if (native_keyset == NULL) {
		throw_NullPointerException(env, "handle is null");
		return;
	}

	if (key == NULL) {
		throw_NullPointerException(env, "key is null");
		return;
	}

	marisa::Key* native_key = get_key(env, key);
	if (native_keyset == NULL) {
		throw_NullPointerException(env, "key is null");
		return;
	}

	try {
		native_keyset->push_back(*native_key, (char)end_marker);
	} catch (const marisa::Exception& ex) {
		throw_MarisaException(env, ex.filename(), ex.line(), ex.error_code(), ex.error_message());
		return;
	}
}
JNIEXPORT void JNICALL Java_jp_marisa_KeysetNative_swap(JNIEnv *env, jobject pthis, jobject rhs) {
	marisa::Keyset* native_keyset = ensure_create_keyset(env, pthis);
	if (native_keyset == NULL) {
		throw_NullPointerException(env, "handle is null");
		return;
	}

	if (rhs == NULL) {
		throw_NullPointerException(env, "rhs is null");
		return;
	}

	marisa::Keyset* native_rhs = ensure_create_keyset(env, rhs);
	if (native_rhs == NULL) {
		throw_NullPointerException(env, "rhs is null");
		return;
	}

	try {
		native_keyset->swap(*native_rhs);
	} catch (const marisa::Exception& ex) {
		throw_MarisaException(env, ex.filename(), ex.line(), ex.error_code(), ex.error_message());
		return;
	}
}
JNIEXPORT void JNICALL Java_jp_marisa_KeysetNative_push_1back___3BIIF(JNIEnv *env, jobject pthis, jbyteArray ptr, jint start, jint length, jfloat weight) {
	marisa::Keyset* native_keyset = ensure_create_keyset(env, pthis);
	if (native_keyset == NULL) {
		throw_NullPointerException(env, "handle is null");
		return;
	}

	if (ptr == NULL) {
		throw_NullPointerException(env, "ptr is null");
		return;
	}

	jbyte* native_ptr = env->GetByteArrayElements(ptr, NULL);
	native_ptr += start;

	try {
		native_keyset->push_back((const char *)native_ptr, length, weight);
	} catch (const marisa::Exception& ex) {
		env->ReleaseByteArrayElements(ptr, native_ptr, JNI_ABORT);

		throw_MarisaException(env, ex.filename(), ex.line(), ex.error_code(), ex.error_message());
		return;
	}

	env->ReleaseByteArrayElements(ptr, native_ptr, JNI_ABORT);
}
  /*
   * Function: getFileCon
   * Purpose: retrieves the context associated with the given path in the file system
   * Parameters:
   *        path: given path in the file system
   * Returns:
   *        string representing the security context string of the file object
   *        the string may be NULL if an error occured
   * Exceptions: NullPointerException if the path object is null
   */
  static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
#ifdef HAVE_SELINUX
    if (isSELinuxDisabled)
      return NULL;

    if (path == NULL) {
      throw_NullPointerException(env, "Trying to check security context of a null path.");
      return NULL;
    }

    const char *objectPath = env->GetStringUTFChars(path, NULL);

    security_context_t context = NULL;
    jstring securityString = NULL;

    if (getfilecon(objectPath, &context) == -1)
      goto bail;

    ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);

    securityString = env->NewStringUTF(context);

  bail:
    if (context != NULL)
      freecon(context);

    env->ReleaseStringUTFChars(path, objectPath);

    return securityString;
#else
    return NULL;
#endif
  }
JNIEXPORT void JNICALL Java_jp_marisa_AgentNative_set_1query___3BII(JNIEnv *env, jobject pthis, jbyteArray str, jint start, jint length) {
	marisa::Agent* native_agent = ensure_create_agent(env, pthis);
	if (native_agent == NULL) {
		throw_NullPointerException(env, "handle is null");
		return;
	}

	// marisa::Agent::set_query set only pointer address.
	// so, we need copy of str.
	jbyte* native_str = env->GetByteArrayElements(str, NULL);
	native_str += start;

	char* copy_str = new char[length];
	memcpy(copy_str, native_str, length);

	env->ReleaseByteArrayElements(str, native_str, JNI_ABORT);

	try {
		native_agent->set_query(copy_str, length);
	} catch (const marisa::Exception& ex) {
		throw_MarisaException(env, ex.filename(), ex.line(), ex.error_code(), ex.error_message());
		return;
	}

	jlong handle = get_stringBufferHandle_value(env, pthis);
	if (handle != -1) {
		delete [] (char *)handle;
	}
	set_stringBufferHandle_value(env, pthis, (jlong)copy_str);
}
static void
acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)
{
    if (idObj == NULL) {
        throw_NullPointerException(env, "id is null");
        return ;
    }

    const char *id = env->GetStringUTFChars(idObj, NULL);

    acquire_wake_lock(lock, id);

    env->ReleaseStringUTFChars(idObj, id);
}
JNIEXPORT void JNICALL Java_jp_marisa_AgentNative_set_1query__J(JNIEnv *env, jobject pthis, jlong key_id) {
	marisa::Agent* native_agent = ensure_create_agent(env, pthis);
	if (native_agent == NULL) {
		throw_NullPointerException(env, "handle is null");
		return;
	}

	try {
		native_agent->set_query(static_cast<std::size_t>(key_id));
	} catch (const marisa::Exception& ex) {
		throw_MarisaException(env, ex.filename(), ex.line(), ex.error_code(), ex.error_message());
		return;
	}
}
  /*
   * Function: getPeerCon
   * Purpose: retrieves security context of peer socket
   * Parameters:
   *        fileDescriptor: peer socket file as a FileDescriptor object
   * Returns: jstring representing the security_context of socket or NULL if error
   * Exceptions: NullPointerException if fileDescriptor object is NULL
   */
  static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
#ifdef HAVE_SELINUX
    if (isSELinuxDisabled)
      return NULL;

    if (fileDescriptor == NULL) {
      throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
      return NULL;
    }

    security_context_t context = NULL;
    jstring securityString = NULL;

    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);

    if (env->ExceptionOccurred() != NULL) {
      ALOGE("There was an issue with retrieving the file descriptor");
      goto bail;
    }

    if (getpeercon(fd, &context) == -1)
      goto bail;

    ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);

    securityString = env->NewStringUTF(context);

  bail:
    if (context != NULL)
      freecon(context);

    return securityString;
#else
    return NULL;
#endif
  }