/* * Copyright (C) 2013 Emmanuel Engelhart * Copyright (C) 2017 Matthieu Gautier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #ifndef _ANDROID_JNI_UTILS_H #define _ANDROID_JNI_UTILS_H #include #include #include #include #include #if __ANDROID__ #include #define LOG(...) __android_log_print(ANDROID_LOG_ERROR, "kiwix", __VA_ARGS__) #else #define LOG(...) #endif extern pthread_mutex_t globalLock; template void setPtr(JNIEnv* env, jobject thisObj, T* ptr) { jclass thisClass = env->GetObjectClass(thisObj); jfieldID fieldId = env->GetFieldID(thisClass, "nativeHandle", "J"); env->SetLongField(thisObj, fieldId, reinterpret_cast(ptr)); } template void allocate(JNIEnv* env, jobject thisObj, Args && ...args) { T* ptr = new T(std::forward(args)...); setPtr(env, thisObj, ptr); } template T* getPtr(JNIEnv* env, jobject thisObj) { jclass thisClass = env->GetObjectClass(thisObj); jfieldID fidNumber = env->GetFieldID(thisClass, "nativeHandle", "J"); return reinterpret_cast(env->GetLongField(thisObj, fidNumber)); } template void dispose(JNIEnv* env, jobject thisObj) { delete getPtr(env, thisObj); } #define METHOD0(retType, class, name) \ JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ JNIEnv* env, jobject thisObj) #define METHOD(retType, class, name, ...) \ JNIEXPORT retType JNICALL Java_org_kiwix_kiwixlib_##class##_##name( \ JNIEnv* env, jobject thisObj, __VA_ARGS__) inline jfieldID getHandleField(JNIEnv* env, jobject obj) { jclass c = env->GetObjectClass(obj); // J is the type signature for long: return env->GetFieldID(c, "nativeHandle", "J"); } inline jobjectArray createArray(JNIEnv* env, size_t length, const std::string& type_sig) { jclass c = env->FindClass(type_sig.c_str()); return env->NewObjectArray(length, c, NULL); } class Lock { protected: pthread_mutex_t* lock; public: Lock() : lock(&globalLock) { pthread_mutex_lock(lock); } Lock(const Lock&) = delete; Lock& operator=(const Lock&) = delete; Lock(Lock&& other) : lock(&globalLock) { other.lock = nullptr; } virtual ~Lock() { if (lock) { pthread_mutex_unlock(lock); } } }; template class LockedHandle; template class Handle { protected: T* h; public: Handle(T* h) : h(h){}; // No destructor. This must and will be handled by dispose method. static LockedHandle getHandle(JNIEnv* env, jobject obj) { jlong handle = env->GetLongField(obj, getHandleField(env, obj)); return LockedHandle(reinterpret_cast*>(handle)); } static void dispose(JNIEnv* env, jobject obj) { auto lHandle = getHandle(env, obj); auto handle = lHandle.h; delete handle->h; delete handle; } friend class LockedHandle; }; template struct LockedHandle : public Lock { Handle* h; LockedHandle(Handle* h) : h(h) {} T* operator->() { return h->h; } T* operator*() { return h->h; } operator bool() const { return (h->h != nullptr); } operator T*() const { return h->h; } }; template struct JType { }; template<> struct JType{ typedef jboolean type_t; }; template<> struct JType{ typedef jint type_t; }; template<> struct JType{ typedef jlong type_t; }; template<> struct JType { typedef jlong type_t; }; template<> struct JType { typedef jlong type_t; }; template<> struct JType{ typedef jstring type_t; }; template<> struct JType>{ typedef jobjectArray type_t; }; template inline typename JType::type_t c2jni(const T& val, JNIEnv* env) { return static_cast::type_t>(val); } template<> inline jboolean c2jni(const bool& val, JNIEnv* env) { return val ? JNI_TRUE : JNI_FALSE; } template<> inline jstring c2jni(const std::string& val, JNIEnv* env) { return env->NewStringUTF(val.c_str()); } template<> inline jobjectArray c2jni(const std::vector& val, JNIEnv* env) { auto array = createArray(env, val.size(), "java/lang/String"); size_t index = 0; for (auto& elem: val) { auto jElem = c2jni(elem, env); env->SetObjectArrayElement(array, index++, jElem); } return array; } template struct CType { }; template<> struct CType{ typedef bool type_t; }; template<> struct CType{ typedef int type_t; }; template<> struct CType{ typedef long type_t; }; template<> struct CType{ typedef std::string type_t; }; template struct CType{ typedef std::vector::type_t> type_t; }; /* jni2c type conversion functions */ template inline typename CType::type_t jni2c(const T& val, JNIEnv* env) { return static_cast::type_t>(val); } template<> inline bool jni2c(const jboolean& val, JNIEnv* env) { return val == JNI_TRUE; } template<> inline std::string jni2c(const jstring& val, JNIEnv* env) { const char* chars = env->GetStringUTFChars(val, 0); std::string ret(chars); env->ReleaseStringUTFChars(val, chars); return ret; } template inline typename CType::type_t jni2c(const jobjectArray& val, JNIEnv* env) { jsize length = env->GetArrayLength(val); typename CType::type_t v(length); int i; for (i = 0; i < length; i++) { U obj = (U) env->GetObjectArrayElement(val, i); auto cobj = jni2c(obj, env); v.push_back(cobj); } return v; } /* Method to deal with variable passed by reference */ inline std::string getStringObjValue(const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID objFid = env->GetFieldID(objClass, "value", "Ljava/lang/String;"); jstring jstr = (jstring)env->GetObjectField(obj, objFid); return jni2c(jstr, env); } inline void setStringObjValue(const std::string& value, const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID objFid = env->GetFieldID(objClass, "value", "Ljava/lang/String;"); env->SetObjectField(obj, objFid, c2jni(value, env)); } inline void setIntObjValue(const int value, const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID objFid = env->GetFieldID(objClass, "value", "I"); env->SetIntField(obj, objFid, value); } inline void setBoolObjValue(const bool value, const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID objFid = env->GetFieldID(objClass, "value", "Z"); env->SetIntField(obj, objFid, c2jni(value, env)); } inline void setPairObjValue(const std::string& filename, const int offset, const jobject obj, JNIEnv* env) { jclass objClass = env->GetObjectClass(obj); jfieldID filenameFid = env->GetFieldID(objClass, "filename", "Ljava/lang/String;"); env->SetObjectField(obj, filenameFid, c2jni(filename, env)); jfieldID offsetFid = env->GetFieldID(objClass, "offset", "I"); env->SetIntField(obj, offsetFid, offset); } #endif // _ANDROID_JNI_UTILS_H