diff options
author | Hoa V. DINH <dinh.viet.hoa@gmail.com> | 2015-01-04 00:21:01 -0800 |
---|---|---|
committer | Hoa V. DINH <dinh.viet.hoa@gmail.com> | 2015-01-04 00:21:01 -0800 |
commit | 8aa7e6dc95a3794d92b248e172df1b4a1c8a5271 (patch) | |
tree | 19d12d60e67b0fe56e3356733b5e0c5218633009 /src/java/TypesUtils.cpp | |
parent | 631c541e7b5ef5ac0930e6b1ace7afab0c52b298 (diff) |
Added java bindings for Android
Diffstat (limited to 'src/java/TypesUtils.cpp')
-rw-r--r-- | src/java/TypesUtils.cpp | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/src/java/TypesUtils.cpp b/src/java/TypesUtils.cpp new file mode 100644 index 00000000..7c500e84 --- /dev/null +++ b/src/java/TypesUtils.cpp @@ -0,0 +1,518 @@ +#include "TypesUtils.h" + +#include "MCValuePrivate.h" +#include "JavaHandle.h" +#include <libetpan/libetpan.h> +#include "MCDefines.h" +#include "MCLog.h" + +using namespace mailcore; + +static chash * cppClassHash = NULL; +static chash * javaClassHash = NULL; + +/* + case jniBoolean: name += "Z"; break; + case jniVoid: name += "V"; break; + case jniByte: name += "B"; break; + case jniChar: name += "C"; break; + case jniShort: name += "S"; break; + case jniInt: name += "I"; break; + case jniLong: name += "J"; break; + case jniFloat: name += "F"; break; + case jniDouble: name += "D"; break; +*/ + +static void init(void); +static void real_init(void); + +jobject mailcore::rangeToJava(JNIEnv * env, Range range) +{ + jclass cls = env->FindClass("com/libmailcore/Range"); + jmethodID constructor = env->GetMethodID(cls, "<init>", "(JJ)V"); + jobject javaObject = env->NewObject(cls, constructor, (jlong) range.location, (jlong) range.length); + return javaObject; +} + +Range mailcore::rangeFromJava(JNIEnv * env, jobject obj) +{ + jclass cls = env->GetObjectClass(obj); + jfieldID locationField = env->GetFieldID(cls, "location", "J"); + jfieldID lengthField = env->GetFieldID(cls, "length", "J"); + jlong location = env->GetLongField(obj, locationField); + jlong length = env->GetLongField(obj, lengthField); + return RangeMake((uint64_t) location, (uint64_t) length); +} + +time_t mailcore::javaDateToTime(JNIEnv * env, jobject date) +{ + jclass javaClass = env->GetObjectClass(date); + jmethodID method = env->GetMethodID(javaClass, "getTime", "()J"); + jlong value = env->CallLongMethod(date, method); + return (time_t) (value / 1000LL); +} + +jobject mailcore::timeToJavaDate(JNIEnv * env, time_t t) +{ + jclass cls = env->FindClass("java/util/Date"); + jmethodID constructor = env->GetMethodID(cls, "<init>", "(J)V"); + jobject javaDate = env->NewObject(cls, constructor, ((jlong) t ) * 1000LL); + return javaDate; +} + +void mailcore::MCJNIRegisterNativeClass(const std::type_info * info, ObjectToJavaConverter converter) +{ + MCLogEnabled = 1; + MCLog("MCJNIRegisterNativeClass"); + init(); + + chashdatum key; + chashdatum value; + MCLog("info: %p", info); +#ifdef __LIBCPP_TYPEINFO + size_t hash_value = info->hash_code(); + MCLog("info hash: %i", (int) hash_value); + key.data = &hash_value; + key.len = sizeof(hash_value); +#else + MCLog("info name: %s", info->name()); + key.data = (void *) info->name(); + key.len = (unsigned int) strlen(info->name()); +#endif + value.data = (void *) converter; + value.len = 0; + chash_set(cppClassHash, &key, &value, NULL); +} + +void mailcore::MCJNIRegisterJavaClass(const char * className, JavaToObjectConverter converter) +{ + MCLogEnabled = 1; + MCLog("MCJNIRegisterJavaClass %s", className); + init(); + + chashdatum key; + chashdatum value; + key.data = (void *) className; + key.len = strlen(className); + value.data = (void *) converter; + value.len = 0; + chash_set(javaClassHash, &key, &value, NULL); +} + +static jobject valueObjectToJavaConverter(JNIEnv * env, Object * obj) +{ + jclass cls; + jmethodID constructor; + Value * value = (Value *) obj; + jobject result; + switch (value->type()) { + // boolean, byte, character, long, int, short, double, float + case mailcore::ValueTypeNone: + MCAssert(0); + break; + case mailcore::ValueTypeBool: + // bool + cls = env->FindClass("java/util/Boolean"); + constructor = env->GetMethodID(cls, "<init>", "(Z)V"); + result = env->NewObject(cls, constructor, value->boolValue()); + break; + case mailcore::ValueTypeChar: + // byte + cls = env->FindClass("java/util/Byte"); + constructor = env->GetMethodID(cls, "<init>", "(B)V"); + result = env->NewObject(cls, constructor, value->charValue()); + break; + case mailcore::ValueTypeUnsignedChar: + // short + cls = env->FindClass("java/util/Short"); + constructor = env->GetMethodID(cls, "<init>", "(S)V"); + result = env->NewObject(cls, constructor, value->unsignedCharValue()); + break; + case mailcore::ValueTypeShort: + // short + cls = env->FindClass("java/util/Short"); + constructor = env->GetMethodID(cls, "<init>", "(S)V"); + result = env->NewObject(cls, constructor, value->shortValue()); + break; + case mailcore::ValueTypeUnsignedShort: + // int + cls = env->FindClass("java/util/Integer"); + constructor = env->GetMethodID(cls, "<init>", "(I)V"); + result = env->NewObject(cls, constructor, value->intValue()); + break; + case mailcore::ValueTypeInt: + // int + cls = env->FindClass("java/util/Integer"); + constructor = env->GetMethodID(cls, "<init>", "(I)V"); + result = env->NewObject(cls, constructor, value->intValue()); + break; + case mailcore::ValueTypeUnsignedInt: + // long + cls = env->FindClass("java/util/Long"); + constructor = env->GetMethodID(cls, "<init>", "(J)V"); + result = env->NewObject(cls, constructor, value->unsignedIntValue()); + break; + case mailcore::ValueTypeLong: + // long + cls = env->FindClass("java/util/Long"); + constructor = env->GetMethodID(cls, "<init>", "(J)V"); + result = env->NewObject(cls, constructor, value->longValue()); + break; + case mailcore::ValueTypeUnsignedLong: + // long + cls = env->FindClass("java/util/Long"); + constructor = env->GetMethodID(cls, "<init>", "(J)V"); + result = env->NewObject(cls, constructor, value->unsignedLongValue()); + break; + case mailcore::ValueTypeLongLong: + // long + cls = env->FindClass("java/util/Long"); + constructor = env->GetMethodID(cls, "<init>", "(J)V"); + result = env->NewObject(cls, constructor, value->longLongValue()); + break; + case mailcore::ValueTypeUnsignedLongLong: + // long - might break + cls = env->FindClass("java/util/Long"); + constructor = env->GetMethodID(cls, "<init>", "(J)V"); + result = env->NewObject(cls, constructor, value->unsignedLongLongValue()); + break; + case mailcore::ValueTypeFloat: + // float + cls = env->FindClass("java/util/Float"); + constructor = env->GetMethodID(cls, "<init>", "(F)V"); + result = env->NewObject(cls, constructor, value->floatValue()); + break; + case mailcore::ValueTypeDouble: + // double + cls = env->FindClass("java/util/Double"); + constructor = env->GetMethodID(cls, "<init>", "(D)V"); + result = env->NewObject(cls, constructor, value->doubleValue()); + break; + case mailcore::ValueTypePointer: + MCAssert(0); + break; + case mailcore::ValueTypeData: + MCAssert(0); + break; + } + return result; +} + +static jobject dataObjectToJavaConverter(JNIEnv * env, Object * obj) +{ + Data * data = (Data *) obj; + jbyteArray result = env->NewByteArray(data->length()); + env->SetByteArrayRegion(result, 0, (jsize) data->length(), (const jbyte *) data->bytes()); + return result; +} + +static jobject stringObjectToJavaConverter(JNIEnv * env, Object * obj) +{ + String * str = (String *) obj; + return env->NewString((const jchar *) str->unicodeCharacters(), (jsize) str->length()); +} + +static jobject hashmapObjectToJavaConverter(JNIEnv * env, Object * obj) +{ + HashMap * hashMap = (HashMap *) obj; + jclass cls = env->FindClass("java/util/HashMap"); + jmethodID constructor = env->GetMethodID(cls, "<init>", "(I)V"); + jobject javaHashMap = env->NewObject(cls, constructor, hashMap->count()); + jmethodID method = env->GetMethodID(cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)V"); + Array * keys = hashMap->allKeys(); + for(unsigned int i = 0 ; i < keys->count() ; i ++) { + Object * key = keys->objectAtIndex(i); + jobject javaKey = mcObjectToJava(env, key); + Object * value = hashMap->objectForKey(key); + jobject javaValue = mcObjectToJava(env, value); + env->CallVoidMethod(javaHashMap, method, javaKey, javaValue); + } + return javaHashMap; +} + +static jobject arrayObjectToJavaConverter(JNIEnv * env, Object * obj) +{ + Array * array = (Array *) obj; + jclass cls = env->FindClass("java/util/Vector"); + jmethodID constructor = env->GetMethodID(cls, "<init>", "(I)V"); + jobject javaVector = env->NewObject(cls, constructor, array->count()); + jmethodID method = env->GetMethodID(cls, "add", "(Ljava/lang/Object;)Z"); + MCLog("add method %p", method); + for(unsigned int i = 0 ; i < array->count() ; i ++) { + MCLog("converting object %s", MCUTF8(array->objectAtIndex(i))); + jobject javaObject = mcObjectToJava(env, array->objectAtIndex(i)); + MCLog("add object %p", javaObject); + env->CallBooleanMethod(javaVector, method, javaObject); + MCLog("added object %p", javaObject); + } + MCLog("array converted"); + return javaVector; +} + +static Object * booleanJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "booleanValue", "()B"); + jboolean value = env->CallBooleanMethod(obj, method); + return Value::valueWithBoolValue(value); +} + +static Object * byteJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "byteValue", "()B"); + jbyte value = env->CallByteMethod(obj, method); + return Value::valueWithShortValue(value); +} + +static Object * characterJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "charValue", "()C"); + jchar value = env->CallCharMethod(obj, method); + return Value::valueWithShortValue(value); +} + +static Object * longJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "longValue", "()J"); + jlong value = env->CallLongMethod(obj, method); + return Value::valueWithLongLongValue(value); +} + +static Object * integerJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "intValue", "()I"); + jint value = env->CallIntMethod(obj, method); + return Value::valueWithIntValue(value); +} + +static Object * shortJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "shortValue", "()S"); + jshort value = env->CallShortMethod(obj, method); + return Value::valueWithShortValue(value); +} + +static Object * doubleJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "doubleValue", "()D"); + jdouble value = env->CallDoubleMethod(obj, method); + return Value::valueWithDoubleValue(value); +} + +static Object * floatJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "floatValue", "()F"); + jfloat value = env->CallFloatMethod(obj, method); + return Value::valueWithFloatValue(value); +} + +static Object * dataJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jsize len = env->GetArrayLength((jarray) obj); + jbyte * bytes = env->GetByteArrayElements((jbyteArray) obj, NULL); + Data * result = Data::dataWithBytes((const char *) bytes, len); + env->ReleaseByteArrayElements((jbyteArray) obj, bytes, 0); + return result; +} + +static Object * stringJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + jsize len = env->GetStringLength((jstring) obj); + const jchar * chars = env->GetStringChars((jstring) obj, NULL); + String * result = String::stringWithCharacters(chars, len); + env->ReleaseStringChars((jstring) obj, chars); + return result; +} + +static bool isJavaMap(JNIEnv * env, jobject obj) +{ + jclass cls = env->FindClass("java/util/Map"); + return env->IsInstanceOf(obj, cls); +} + +static Object * hashmapJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + HashMap * result = HashMap::hashMap(); + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "entrySet", "()Ljava/util/Set;"); + jobject entrySet = (jobjectArray) env->CallObjectMethod(obj, method); + javaClass = env->GetObjectClass(entrySet); + method = env->GetMethodID(javaClass, "toArray", "()[Ljava/lang/Object;"); + jobjectArray array = (jobjectArray) env->CallObjectMethod(obj, method); + int count = (int) env->GetArrayLength(array); + for(int i = 0 ; i < count ; i ++) { + jobject entry = env->GetObjectArrayElement(array, i); + javaClass = env->GetObjectClass(entry); + method = env->GetMethodID(javaClass, "getKey", "()Ljava/lang/Object;"); + jobject key = env->CallObjectMethod(obj, method); + Object * mcKey = javaToMCObject(env, key); + method = env->GetMethodID(javaClass, "getValue", "()Ljava/lang/Object;"); + jobject value = env->CallObjectMethod(obj, method); + Object * mcValue = javaToMCObject(env, value); + result->setObjectForKey(mcKey, mcValue); + } + return result; +} + +static bool isJavaList(JNIEnv * env, jobject obj) +{ + jclass cls = env->FindClass("java/util/List"); + return env->IsInstanceOf(obj, cls); +} + +static Object * arrayJavaToObjectConverter(JNIEnv * env, jobject obj) +{ + Array * result = Array::array(); + jclass javaClass = env->GetObjectClass(obj); + jmethodID method = env->GetMethodID(javaClass, "toArray", "()[Ljava/lang/Object;"); + jobjectArray array = (jobjectArray) env->CallObjectMethod(obj, method); + int count = (int) env->GetArrayLength(array); + for(int i = 0 ; i < count ; i ++) { + jobject item = env->GetObjectArrayElement(array, i); + Object * mcItem = javaToMCObject(env, item); + result->addObject(mcItem); + } + return result; +} + +static bool isNativeObject(JNIEnv * env, jobject obj) +{ + jclass cls = env->FindClass("com/libmailcore/NativeObject"); + return env->IsInstanceOf(obj, cls); +} + +static void setupBasicConverters(void) +{ + MCLog("register value"); + MCJNIRegisterNativeClass(&typeid(mailcore::Value), (ObjectToJavaConverter *) valueObjectToJavaConverter); + MCLog("register data"); + MCJNIRegisterNativeClass(&typeid(mailcore::Data), (ObjectToJavaConverter *) dataObjectToJavaConverter); + MCLog("register string"); + MCJNIRegisterNativeClass(&typeid(mailcore::String), (ObjectToJavaConverter *) stringObjectToJavaConverter); + MCLog("register hashmap"); + MCJNIRegisterNativeClass(&typeid(mailcore::HashMap), (ObjectToJavaConverter *) hashmapObjectToJavaConverter); + MCLog("register array"); + MCJNIRegisterNativeClass(&typeid(mailcore::Array), (ObjectToJavaConverter *) arrayObjectToJavaConverter); + + MCLog("register java bool"); + MCJNIRegisterJavaClass("java.lang.Boolean", (JavaToObjectConverter *) booleanJavaToObjectConverter); + MCLog("register java byte"); + MCJNIRegisterJavaClass("java.lang.Byte", (JavaToObjectConverter *) byteJavaToObjectConverter); + MCLog("register java char"); + MCJNIRegisterJavaClass("java.lang.Character", (JavaToObjectConverter *) characterJavaToObjectConverter); + MCLog("register java long"); + MCJNIRegisterJavaClass("java.lang.Long", (JavaToObjectConverter *) longJavaToObjectConverter); + MCLog("register java int"); + MCJNIRegisterJavaClass("java.lang.Integer", (JavaToObjectConverter *) integerJavaToObjectConverter); + MCLog("register java short"); + MCJNIRegisterJavaClass("java.lang.Short", (JavaToObjectConverter *) shortJavaToObjectConverter); + MCLog("register java double"); + MCJNIRegisterJavaClass("java.lang.Double", (JavaToObjectConverter *) doubleJavaToObjectConverter); + MCLog("register java float"); + MCJNIRegisterJavaClass("java.lang.Float", (JavaToObjectConverter *) floatJavaToObjectConverter); + MCLog("register java array of bytes"); + MCJNIRegisterJavaClass("[B", (JavaToObjectConverter *) dataJavaToObjectConverter); + MCLog("register java string"); + MCJNIRegisterJavaClass("java.lang.String", (JavaToObjectConverter *) stringJavaToObjectConverter); +} + +Object * mailcore::javaToMCObject(JNIEnv * env, jobject obj) +{ + if (obj == NULL) { + return NULL; + } + + if (isNativeObject(env, obj)) { + return (Object *) getHandle(env, obj); + } + else if (isJavaMap(env, obj)) { + return hashmapJavaToObjectConverter(env, obj); + } + else if (isJavaMap(env, obj)) { + return arrayJavaToObjectConverter(env, obj); + } + else { + Object * result = NULL; + + jclass javaClass = env->GetObjectClass(obj); + jclass classClass = env->GetObjectClass(javaClass); + jmethodID mid = env->GetMethodID(classClass, "getName", "()Ljava/lang/String;"); + jstring strObj = (jstring) env->CallObjectMethod(javaClass, mid); + const char * str = env->GetStringUTFChars(strObj, NULL); + MCLog("class: %s", str); + chashdatum key; + chashdatum value; + key.data = (void *) str; + key.len = strlen(str); + int r = chash_get(javaClassHash, &key, &value); + if (r == 0) { + JavaToObjectConverter * converter = (JavaToObjectConverter *) value.data; + result = converter(env, obj); + MCLog("result: %s", MCUTF8(result)); + } + else { + MCLog("converter not found: %s", str); + MCAssert(0); + } + env->ReleaseStringUTFChars(strObj, str); + + return result; + } +} + +jobject mailcore::mcObjectToJava(JNIEnv * env, Object * obj) +{ + MCLog("converter to java: %s", MCUTF8(obj)); + if (obj == NULL) { + return NULL; + } + + const std::type_info * info = &typeid(* obj); + chashdatum key; + chashdatum value; +#ifdef __LIBCPP_TYPEINFO + size_t hash_value = info->hash_code(); + MCLog("converter to java: %i", (int) hash_value); + key.data = &hash_value; + key.len = sizeof(hash_value); +#else + key.data = (void *) info->name(); + key.len = (unsigned int) strlen(info->name()); +#endif + int r = chash_get(cppClassHash, &key, &value); + if (r < 0) { + MCLog("converter not found: %s", MCUTF8(obj)); + MCAssert(0); + } + ObjectToJavaConverter * converter = (ObjectToJavaConverter *) value.data; + return converter(env, obj); +} + +static void init(void) +{ + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, real_init); +} + +static void real_init(void) +{ + MCLogEnabled = 1; + MCLog("real_init"); + MCLog("init cppClassHash"); + cppClassHash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); + MCLog("init javaClassHash"); + javaClassHash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); +} + +void mailcore::MCTypesUtilsInit(void) +{ + MCLog("basic converters"); + setupBasicConverters(); +} |