#include "jni_util.h" #include #include #include #include using namespace util; jfieldID util::getFieldID(JNIEnv *env, jobject object, const char *field, const char *sig) { if (env == NULL || object == NULL || field == NULL || sig == NULL) return NULL; jclass clazz = env->GetObjectClass(object); jfieldID fieldID = env->GetFieldID(clazz, field, sig); if (fieldID == NULL) { const char *className = getClassName(env, clazz); const std::string full = std::string(className) + "." + field; throwNoSuchFieldError(env, full.c_str()); freeClassName(className); return NULL; } return fieldID; } jmethodID util::getMethodID(JNIEnv *env, jobject object, const char *method, const char *sig) { if (env == NULL || object == NULL || method == NULL || sig == NULL) return NULL; jclass clazz = env->GetObjectClass(object); jmethodID methodID = env->GetMethodID(clazz, method, sig); if (methodID == NULL) { const char *className = getClassName(env, clazz); const std::string full = std::string(className) + "." + method + sig; throwNoSuchMethodError(env, full.c_str()); freeClassName(className); env->DeleteLocalRef(clazz); return NULL; } env->DeleteLocalRef(clazz); return methodID; } void util::setByteArrayField(JNIEnv *env, jobject object, const char *field, jbyteArray value) { jfieldID fieldID = getFieldID(env, object, field, "[B"); if (fieldID == NULL) return; env->SetObjectField(object, fieldID, value); } void util::setByteArrayField(JNIEnv *env, jobject object, const char *field, const char *string) { jsize len = (jsize)strlen(string); jbyteArray byteArray = env->NewByteArray(len); env->SetByteArrayRegion(byteArray, 0, len, (const signed char *)string); setByteArrayField(env, object, field, byteArray); } jbyteArray util::getByteArrayField(JNIEnv *env, jobject object, const char *field) { jfieldID fieldID = getFieldID(env, object, field, "[B"); if (fieldID == NULL) return NULL; return (jbyteArray)env->GetObjectField(object, fieldID); } char **util::jbyteArray2DToCharArray(JNIEnv *env, jobjectArray array) { jboolean copy = false; jsize len = env->GetArrayLength(array); char **result = new char*[len]; for (jsize i = 0; i < len; i++) { jbyteArray byteArrayObject = (jbyteArray)env->GetObjectArrayElement(array, i); char *elem = (char *)env->GetByteArrayElements(byteArrayObject, ©); jsize slen = strlen(elem); char *nstring = new char[slen + 1LL]; nstring[slen] = 0; memcpy(nstring, elem, slen); result[i] = nstring; } return result; } void util::delete2DByteArray(int count, char **array) { for (int i = 0; i < count; i++) { delete[] array[i]; array[i] = NULL; } delete[] array; } void util::setLongField(JNIEnv *env, jobject object, const char *field, jlong value) { jfieldID fieldID = getFieldID(env, object, field, "J"); if (fieldID == NULL) return; env->SetLongField(object, fieldID, value); } jlong util::getLongField(JNIEnv *env, jobject object, const char *field) { jfieldID fieldID = getFieldID(env, object, field, "J"); if (fieldID == NULL) return 0LL; return env->GetLongField(object, fieldID); } void util::setIntField(JNIEnv *env, jobject object, const char *field, jint value) { jfieldID fieldID = getFieldID(env, object, field, "I"); if (fieldID == NULL) return; env->SetIntField(object, fieldID, value); } jint util::getIntField(JNIEnv *env, jobject object, const char *field) { jfieldID fieldID = getFieldID(env, object, field, "I"); if (fieldID == NULL) return 0; return env->GetIntField(object, fieldID); } int util::callIntMethod(JNIEnv *env, jobject object, const char *method, const char *sig, ...) { jmethodID methodID = getMethodID(env, object, method, sig); if (methodID == NULL) return 0; va_list args; int result; va_start(args, sig); result = env->CallIntMethodV(object, methodID, args); va_end(args); return result; } void util::setObjectField(JNIEnv *env, jobject object, const char *field, jobject value) { jfieldID fieldID = getFieldID(env, object, field, "Ljava/lang/Object;"); if (fieldID == NULL) return; env->SetObjectField(object, fieldID, value); } jobject util::getObjectField(JNIEnv *env, jobject object, const char *field) { jfieldID fieldID = getFieldID(env, object, field, "Ljava/lang/Object;"); if (fieldID == NULL) return 0; return env->GetObjectField(object, fieldID); } jobject util::toWrapperType(JNIEnv *env, jboolean value) { jclass clazz; static const char *const className = "java/lang/Boolean"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(Z)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jbyte value) { jclass clazz; static const char *const className = "java/lang/Byte"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(Z)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jchar value) { jclass clazz; static const char *const className = "java/lang/Character"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(C)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jshort value) { jclass clazz; static const char *const className = "java/lang/Short"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(S)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jint value) { jclass clazz; static const char *const className = "java/lang/Integer"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(I)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jlong value) { jclass clazz; static const char *const className = "java/lang/Long"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(J)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jfloat value) { jclass clazz; static const char *const className = "java/lang/Float"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(F)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jobject util::toWrapperType(JNIEnv *env, jdouble value) { jclass clazz; static const char *const className = "java/lang/Double"; clazz = env->FindClass(className); if (!clazz) { throwNoClassDefError(env, className); return NULL; } jmethodID methodID = env->GetMethodID(clazz, "", "(D)V"); jobject result = env->NewObject(clazz, methodID, value); return result; } jboolean util::toBoolean(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jboolean on NULL jobject"); return JNI_FALSE; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "Z"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetBooleanField(wrapped, fieldID); } jbyte util::toByte(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jbyte on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "B"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetByteField(wrapped, fieldID); } jchar util::toChar(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jchar on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "C"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetCharField(wrapped, fieldID); } jshort util::toShort(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jshort on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "S"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetShortField(wrapped, fieldID); } jint util::toInt(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jint on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "I"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetIntField(wrapped, fieldID); } jlong util::toLong(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jlong on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "J"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetLongField(wrapped, fieldID); } jfloat util::toFloat(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jfloat on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "F"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetFloatField(wrapped, fieldID); } jdouble util::toDouble(JNIEnv *env, jobject wrapped) { if (!wrapped) { throwNullPointerException(env, "attempting to get wrapped jdouble on NULL jobject"); return 0; } jclass clazz = env->GetObjectClass(wrapped); jfieldID fieldID = env->GetFieldID(clazz, "value", "D"); if (fieldID == NULL) { throwNoSuchFieldError(env, "value"); return 0; } return env->GetDoubleField(wrapped, fieldID); } jint util::throwNoClassDefError(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "java/lang/NoClassDefFoundError"; exClass = env->FindClass(className); if (exClass == NULL) throw std::exception("Failed to find java.lang.NoClassDefFoundError"); return env->ThrowNew(exClass, message); } jint util::throwNullPointerException(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "java/lang/NullPointerException"; exClass = env->FindClass(className); if (exClass == NULL) return throwNoClassDefError(env, className); return env->ThrowNew(exClass, message); } jint util::throwNoSuchMethodError(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "java/lang/NoSuchMethodError"; exClass = env->FindClass(className); if (exClass == NULL) return throwNoClassDefError(env, className); return env->ThrowNew(exClass, message); } jint util::throwNoSuchFieldError(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "java/lang/NoSuchFieldError"; exClass = env->FindClass(className); if (exClass == NULL) return throwNoClassDefError(env, className); return env->ThrowNew(exClass, message); } jint util::throwAllocationError(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "com/artifex/gsjava/util/AllocationError"; exClass = env->FindClass(className); if (exClass == NULL) return throwNoClassDefError(env, className); return env->ThrowNew(exClass, message); } jint util::throwIllegalArgumentException(JNIEnv *env, const char *message) { if (env == NULL) return -1; jclass exClass; static const char *const className = "java/lang/IllegalArgumentException"; exClass = env->FindClass(className); if (exClass == NULL) return throwNoClassDefError(env, className); return env->ThrowNew(exClass, message); } const char *util::getClassName(JNIEnv *env, jclass clazz) { jclass clsClazz = env->GetObjectClass(clazz); jmethodID methodId = env->GetMethodID(clsClazz, "getName", "()Ljava/lang/String;"); jstring className = (jstring)env->CallObjectMethod(clazz, methodId); const char *chars = env->GetStringUTFChars(className, NULL); jsize len = env->GetStringLength(className); char *cstr = new char[len + 1LL]; if (cstr == NULL) { env->ReleaseStringUTFChars(className, chars); env->DeleteLocalRef(className); return NULL; } cstr[len] = 0; memcpy(cstr, chars, len); env->ReleaseStringUTFChars(className, chars); env->DeleteLocalRef(className); return cstr; } void util::freeClassName(const char *className) { delete[] className; } util::Reference::Reference(JNIEnv *env) : Reference(m_env, NULL) { } util::Reference::Reference(JNIEnv *env, jobject object) : m_env(env), m_object(NULL) { if (!object) { static const char *const CLASS_NAME = "com/artifex/gsjava/util/Reference"; jclass refClass = env->FindClass(CLASS_NAME); if (refClass == NULL) { throwNoClassDefError(env, CLASS_NAME); return; } jmethodID constructor = env->GetMethodID(refClass, "", "()V"); if (constructor == NULL) { throwNoSuchMethodError(env, "com/artifex/gsjava/util/Reference.()V"); return; } object = m_env->NewObject(refClass, constructor); if (object == NULL) return; } m_object = m_env->NewGlobalRef(object); } util::Reference::~Reference() { if (m_object) m_env->DeleteGlobalRef(m_object); }