1/* 2** 3** Copyright 2009, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#define LOG_TAG "BinaryDictionary" 19#include "utils/Log.h" 20 21#include <stdio.h> 22#include <assert.h> 23#include <unistd.h> 24#include <fcntl.h> 25 26#include <nativehelper/jni.h> 27#include "utils/AssetManager.h" 28#include "utils/Asset.h" 29 30#include "dictionary.h" 31 32// ---------------------------------------------------------------------------- 33 34using namespace latinime; 35 36using namespace android; 37 38static jfieldID sDescriptorField; 39static jfieldID sAssetManagerNativeField; 40static jmethodID sAddWordMethod; 41static jfieldID sDictLength; 42 43// 44// helper function to throw an exception 45// 46static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) 47{ 48 if (jclass cls = env->FindClass(ex)) { 49 char msg[1000]; 50 sprintf(msg, fmt, data); 51 env->ThrowNew(cls, msg); 52 env->DeleteLocalRef(cls); 53 } 54} 55 56static jint latinime_BinaryDictionary_open 57 (JNIEnv *env, jobject object, jobject assetManager, jstring resourceString, 58 jint typedLetterMultiplier, jint fullWordMultiplier) 59{ 60 // Get the native file descriptor from the FileDescriptor object 61 AssetManager *am = (AssetManager*) env->GetIntField(assetManager, sAssetManagerNativeField); 62 if (!am) { 63 LOGE("DICT: Couldn't get AssetManager native peer\n"); 64 return 0; 65 } 66 const char *resourcePath = env->GetStringUTFChars(resourceString, NULL); 67 68 Asset *dictAsset = am->openNonAsset(resourcePath, Asset::ACCESS_BUFFER); 69 if (dictAsset == NULL) { 70 LOGE("DICT: Couldn't get asset %s\n", resourcePath); 71 env->ReleaseStringUTFChars(resourceString, resourcePath); 72 return 0; 73 } 74 75 void *dict = (void*) dictAsset->getBuffer(false); 76 if (dict == NULL) { 77 LOGE("DICT: Dictionary buffer is null\n"); 78 env->ReleaseStringUTFChars(resourceString, resourcePath); 79 return 0; 80 } 81 Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier); 82 dictionary->setAsset(dictAsset); 83 env->SetIntField(object, sDictLength, (jint) dictAsset->getLength()); 84 85 env->ReleaseStringUTFChars(resourceString, resourcePath); 86 return (jint) dictionary; 87} 88 89static int latinime_BinaryDictionary_getSuggestions( 90 JNIEnv *env, jobject object, jint dict, jintArray inputArray, jint arraySize, 91 jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxWords, 92 jint maxAlternatives, jint skipPos, jintArray nextLettersArray, jint nextLettersSize) 93{ 94 Dictionary *dictionary = (Dictionary*) dict; 95 if (dictionary == NULL) 96 return 0; 97 98 int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); 99 int *inputCodes = env->GetIntArrayElements(inputArray, NULL); 100 jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); 101 int *nextLetters = nextLettersArray != NULL ? env->GetIntArrayElements(nextLettersArray, NULL) 102 : NULL; 103 104 int count = dictionary->getSuggestions(inputCodes, arraySize, (unsigned short*) outputChars, frequencies, 105 maxWordLength, maxWords, maxAlternatives, skipPos, nextLetters, nextLettersSize); 106 107 env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); 108 env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); 109 env->ReleaseCharArrayElements(outputArray, outputChars, 0); 110 if (nextLetters) { 111 env->ReleaseIntArrayElements(nextLettersArray, nextLetters, 0); 112 } 113 114 return count; 115} 116 117static jboolean latinime_BinaryDictionary_isValidWord 118 (JNIEnv *env, jobject object, jint dict, jcharArray wordArray, jint wordLength) 119{ 120 Dictionary *dictionary = (Dictionary*) dict; 121 if (dictionary == NULL) return (jboolean) false; 122 123 jchar *word = env->GetCharArrayElements(wordArray, NULL); 124 jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength); 125 env->ReleaseCharArrayElements(wordArray, word, JNI_ABORT); 126 127 return result; 128} 129 130static void latinime_BinaryDictionary_close 131 (JNIEnv *env, jobject object, jint dict) 132{ 133 Dictionary *dictionary = (Dictionary*) dict; 134 ((Asset*) dictionary->getAsset())->close(); 135 delete (Dictionary*) dict; 136} 137 138// ---------------------------------------------------------------------------- 139 140static JNINativeMethod gMethods[] = { 141 {"openNative", "(Landroid/content/res/AssetManager;Ljava/lang/String;II)I", 142 (void*)latinime_BinaryDictionary_open}, 143 {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, 144 {"getSuggestionsNative", "(I[II[C[IIIII[II)I", (void*)latinime_BinaryDictionary_getSuggestions}, 145 {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord} 146}; 147 148static int registerNativeMethods(JNIEnv* env, const char* className, 149 JNINativeMethod* gMethods, int numMethods) 150{ 151 jclass clazz; 152 153 clazz = env->FindClass(className); 154 if (clazz == NULL) { 155 fprintf(stderr, 156 "Native registration unable to find class '%s'\n", className); 157 return JNI_FALSE; 158 } 159 if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { 160 fprintf(stderr, "RegisterNatives failed for '%s'\n", className); 161 return JNI_FALSE; 162 } 163 164 return JNI_TRUE; 165} 166 167static int registerNatives(JNIEnv *env) 168{ 169 const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; 170 jclass clazz; 171 172 clazz = env->FindClass("java/io/FileDescriptor"); 173 if (clazz == NULL) { 174 LOGE("Can't find %s", "java/io/FileDescriptor"); 175 return -1; 176 } 177 sDescriptorField = env->GetFieldID(clazz, "descriptor", "I"); 178 179 clazz = env->FindClass("android/content/res/AssetManager"); 180 if (clazz == NULL) { 181 LOGE("Can't find %s", "java/io/FileDescriptor"); 182 return -1; 183 } 184 sAssetManagerNativeField = env->GetFieldID(clazz, "mObject", "I"); 185 186 // Get the field pointer for the dictionary length 187 clazz = env->FindClass(kClassPathName); 188 if (clazz == NULL) { 189 LOGE("Can't find %s", kClassPathName); 190 return -1; 191 } 192 sDictLength = env->GetFieldID(clazz, "mDictLength", "I"); 193 194 return registerNativeMethods(env, 195 kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); 196} 197 198/* 199 * Returns the JNI version on success, -1 on failure. 200 */ 201jint JNI_OnLoad(JavaVM* vm, void* reserved) 202{ 203 JNIEnv* env = NULL; 204 jint result = -1; 205 206 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 207 fprintf(stderr, "ERROR: GetEnv failed\n"); 208 goto bail; 209 } 210 assert(env != NULL); 211 212 if (!registerNatives(env)) { 213 fprintf(stderr, "ERROR: BinaryDictionary native registration failed\n"); 214 goto bail; 215 } 216 217 /* success -- return valid version number */ 218 result = JNI_VERSION_1_4; 219 220bail: 221 return result; 222} 223