com_android_inputmethod_latin_BinaryDictionary.cpp revision e93b1f2209e26add7e5c2685990a8ce921fd6e32
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 "LatinIME: jni: BinaryDictionary" 19 20#include "com_android_inputmethod_latin_BinaryDictionary.h" 21#include "dictionary.h" 22#include "jni.h" 23#include "proximity_info.h" 24 25#include <assert.h> 26#include <errno.h> 27#include <stdio.h> 28 29#ifdef USE_MMAP_FOR_DICTIONARY 30#include <sys/mman.h> 31#include <sys/types.h> 32#include <sys/stat.h> 33#include <fcntl.h> 34#else // USE_MMAP_FOR_DICTIONARY 35#include <stdlib.h> 36#endif // USE_MMAP_FOR_DICTIONARY 37 38// ---------------------------------------------------------------------------- 39 40namespace latinime { 41 42// 43// helper function to throw an exception 44// 45static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) { 46 if (jclass cls = env->FindClass(ex)) { 47 char msg[1000]; 48 snprintf(msg, sizeof(msg), fmt, data); 49 env->ThrowNew(cls, msg); 50 env->DeleteLocalRef(cls); 51 } 52} 53 54static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, 55 jstring sourceDir, jlong dictOffset, jlong dictSize, 56 jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, 57 jint maxAlternatives) { 58 PROF_OPEN; 59 PROF_START(66); 60 const char *sourceDirChars = env->GetStringUTFChars(sourceDir, NULL); 61 if (sourceDirChars == NULL) { 62 LOGE("DICT: Can't get sourceDir string"); 63 return 0; 64 } 65 int fd = 0; 66 void *dictBuf = NULL; 67 int adjust = 0; 68#ifdef USE_MMAP_FOR_DICTIONARY 69 /* mmap version */ 70 fd = open(sourceDirChars, O_RDONLY); 71 if (fd < 0) { 72 LOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 73 return 0; 74 } 75 int pagesize = getpagesize(); 76 adjust = dictOffset % pagesize; 77 int adjDictOffset = dictOffset - adjust; 78 int adjDictSize = dictSize + adjust; 79 dictBuf = mmap(NULL, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); 80 if (dictBuf == MAP_FAILED) { 81 LOGE("DICT: Can't mmap dictionary. errno=%d", errno); 82 return 0; 83 } 84 dictBuf = (void *)((char *)dictBuf + adjust); 85#else // USE_MMAP_FOR_DICTIONARY 86 /* malloc version */ 87 FILE *file = NULL; 88 file = fopen(sourceDirChars, "rb"); 89 if (file == NULL) { 90 LOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 91 return 0; 92 } 93 dictBuf = malloc(sizeof(char) * dictSize); 94 if (!dictBuf) { 95 LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); 96 return 0; 97 } 98 int ret = fseek(file, (long)dictOffset, SEEK_SET); 99 if (ret != 0) { 100 LOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno); 101 return 0; 102 } 103 ret = fread(dictBuf, sizeof(char) * dictSize, 1, file); 104 if (ret != 1) { 105 LOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno); 106 return 0; 107 } 108 ret = fclose(file); 109 if (ret != 0) { 110 LOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno); 111 return 0; 112 } 113#endif // USE_MMAP_FOR_DICTIONARY 114 env->ReleaseStringUTFChars(sourceDir, sourceDirChars); 115 116 if (!dictBuf) { 117 LOGE("DICT: dictBuf is null"); 118 return 0; 119 } 120 Dictionary *dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, 121 fullWordMultiplier, maxWordLength, maxWords, maxAlternatives); 122 PROF_END(66); 123 PROF_CLOSE; 124 return (jint)dictionary; 125} 126 127static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict, 128 jint proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, 129 jintArray inputArray, jint arraySize, jint flags, 130 jcharArray outputArray, jintArray frequencyArray) { 131 Dictionary *dictionary = (Dictionary*)dict; 132 if (!dictionary) return 0; 133 ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; 134 135 int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, NULL); 136 int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, NULL); 137 138 int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); 139 int *inputCodes = env->GetIntArrayElements(inputArray, NULL); 140 jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); 141 142 int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes, 143 arraySize, flags, (unsigned short*) outputChars, frequencies); 144 145 env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); 146 env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); 147 env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0); 148 env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0); 149 env->ReleaseCharArrayElements(outputArray, outputChars, 0); 150 151 return count; 152} 153 154static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jint dict, 155 jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, 156 jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams, 157 jint maxAlternatives) { 158 Dictionary *dictionary = (Dictionary*)dict; 159 if (!dictionary) return 0; 160 161 jchar *prevWord = env->GetCharArrayElements(prevWordArray, NULL); 162 int *inputCodes = env->GetIntArrayElements(inputArray, NULL); 163 jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); 164 int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); 165 166 int count = dictionary->getBigrams((unsigned short*) prevWord, prevWordLength, inputCodes, 167 inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams, 168 maxAlternatives); 169 170 env->ReleaseCharArrayElements(prevWordArray, prevWord, JNI_ABORT); 171 env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); 172 env->ReleaseCharArrayElements(outputArray, outputChars, 0); 173 env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); 174 175 return count; 176} 177 178static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jint dict, 179 jcharArray wordArray, jint wordLength) { 180 Dictionary *dictionary = (Dictionary*)dict; 181 if (!dictionary) return (jboolean) false; 182 183 jchar *word = env->GetCharArrayElements(wordArray, NULL); 184 jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength); 185 env->ReleaseCharArrayElements(wordArray, word, JNI_ABORT); 186 187 return result; 188} 189 190static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint dict) { 191 Dictionary *dictionary = (Dictionary*)dict; 192 if (!dictionary) return; 193 void *dictBuf = dictionary->getDict(); 194 if (!dictBuf) return; 195#ifdef USE_MMAP_FOR_DICTIONARY 196 int ret = munmap((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), 197 dictionary->getDictSize() + dictionary->getDictBufAdjust()); 198 if (ret != 0) { 199 LOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); 200 } 201 ret = close(dictionary->getMmapFd()); 202 if (ret != 0) { 203 LOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); 204 } 205#else // USE_MMAP_FOR_DICTIONARY 206 free(dictBuf); 207#endif // USE_MMAP_FOR_DICTIONARY 208 delete dictionary; 209} 210 211// ---------------------------------------------------------------------------- 212 213static JNINativeMethod sMethods[] = { 214 {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open}, 215 {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, 216 {"getSuggestionsNative", "(II[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, 217 {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, 218 {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams} 219}; 220 221static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, 222 int numMethods) { 223 jclass clazz; 224 225 clazz = env->FindClass(className); 226 if (clazz == NULL) { 227 LOGE("Native registration unable to find class '%s'", className); 228 return JNI_FALSE; 229 } 230 if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { 231 LOGE("RegisterNatives failed for '%s'", className); 232 return JNI_FALSE; 233 } 234 235 return JNI_TRUE; 236} 237 238int register_BinaryDictionary(JNIEnv *env) { 239 const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; 240 return registerNativeMethods(env, kClassPathName, sMethods, 241 sizeof(sMethods) / sizeof(sMethods[0])); 242} 243 244}; // namespace latinime 245