com_android_inputmethod_latin_BinaryDictionary.cpp revision f1008c550168e50f930ea1e043000b395ce0f129
1/* 2 * Copyright (C) 2009, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "LatinIME: jni: BinaryDictionary" 18 19#include "binary_format.h" 20#include "correction.h" 21#include "com_android_inputmethod_latin_BinaryDictionary.h" 22#include "defines.h" 23#include "dictionary.h" 24#include "jni.h" 25#include "jni_common.h" 26#include "proximity_info.h" 27 28#include <cassert> 29#include <cerrno> 30#include <cstdio> 31 32#ifdef USE_MMAP_FOR_DICTIONARY 33#include <sys/mman.h> 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <fcntl.h> 37#include <unistd.h> 38#else // USE_MMAP_FOR_DICTIONARY 39#include <cstdlib> 40#endif // USE_MMAP_FOR_DICTIONARY 41 42namespace latinime { 43 44void releaseDictBuf(void *dictBuf, const size_t length, int fd); 45 46static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, 47 jstring sourceDir, jlong dictOffset, jlong dictSize, 48 jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, 49 jint maxPredictions) { 50 PROF_OPEN; 51 PROF_START(66); 52 const char *sourceDirChars = env->GetStringUTFChars(sourceDir, 0); 53 if (sourceDirChars == 0) { 54 AKLOGE("DICT: Can't get sourceDir string"); 55 return 0; 56 } 57 int fd = 0; 58 void *dictBuf = 0; 59 int adjust = 0; 60#ifdef USE_MMAP_FOR_DICTIONARY 61 /* mmap version */ 62 fd = open(sourceDirChars, O_RDONLY); 63 if (fd < 0) { 64 AKLOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 65 return 0; 66 } 67 int pagesize = getpagesize(); 68 adjust = dictOffset % pagesize; 69 int adjDictOffset = dictOffset - adjust; 70 int adjDictSize = dictSize + adjust; 71 dictBuf = mmap(0, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); 72 if (dictBuf == MAP_FAILED) { 73 AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); 74 return 0; 75 } 76 dictBuf = (void *)((char *)dictBuf + adjust); 77#else // USE_MMAP_FOR_DICTIONARY 78 /* malloc version */ 79 FILE *file = 0; 80 file = fopen(sourceDirChars, "rb"); 81 if (file == 0) { 82 AKLOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 83 return 0; 84 } 85 dictBuf = malloc(sizeof(char) * dictSize); 86 if (!dictBuf) { 87 AKLOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); 88 return 0; 89 } 90 int ret = fseek(file, (long)dictOffset, SEEK_SET); 91 if (ret != 0) { 92 AKLOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno); 93 return 0; 94 } 95 ret = fread(dictBuf, sizeof(char) * dictSize, 1, file); 96 if (ret != 1) { 97 AKLOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno); 98 return 0; 99 } 100 ret = fclose(file); 101 if (ret != 0) { 102 AKLOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno); 103 return 0; 104 } 105#endif // USE_MMAP_FOR_DICTIONARY 106 env->ReleaseStringUTFChars(sourceDir, sourceDirChars); 107 108 if (!dictBuf) { 109 AKLOGE("DICT: dictBuf is null"); 110 return 0; 111 } 112 Dictionary *dictionary = 0; 113 if (BinaryFormat::UNKNOWN_FORMAT == BinaryFormat::detectFormat((uint8_t*)dictBuf)) { 114 AKLOGE("DICT: dictionary format is unknown, bad magic number"); 115#ifdef USE_MMAP_FOR_DICTIONARY 116 releaseDictBuf(((char*)dictBuf) - adjust, adjDictSize, fd); 117#else // USE_MMAP_FOR_DICTIONARY 118 releaseDictBuf(dictBuf, 0, 0); 119#endif // USE_MMAP_FOR_DICTIONARY 120 } else { 121 dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, 122 fullWordMultiplier, maxWordLength, maxWords, maxPredictions); 123 } 124 PROF_END(66); 125 PROF_CLOSE; 126 return (jlong)dictionary; 127} 128 129static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, 130 jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, 131 jintArray timesArray, jintArray pointerIdArray, jintArray inputArray, jint arraySize, 132 jint commitPoint, jboolean isGesture, 133 jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, 134 jintArray frequencyArray, jintArray spaceIndexArray, jintArray outputTypesArray) { 135 Dictionary *dictionary = (Dictionary*) dict; 136 if (!dictionary) return 0; 137 ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; 138 int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, 0); 139 int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, 0); 140 int *times = env->GetIntArrayElements(timesArray, 0); 141 int *pointerIds = env->GetIntArrayElements(pointerIdArray, 0); 142 int *frequencies = env->GetIntArrayElements(frequencyArray, 0); 143 int *inputCodes = env->GetIntArrayElements(inputArray, 0); 144 jchar *outputChars = env->GetCharArrayElements(outputArray, 0); 145 int *spaceIndices = env->GetIntArrayElements(spaceIndexArray, 0); 146 int *outputTypes = env->GetIntArrayElements(outputTypesArray, 0); 147 jint *prevWordChars = prevWordForBigrams 148 ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; 149 jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; 150 151 int count; 152 if (isGesture || arraySize > 1) { 153 count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, 154 inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, 155 useFullEditDistance, (unsigned short*) outputChars, frequencies, spaceIndices, 156 outputTypes); 157 } else { 158 count = dictionary->getBigrams(prevWordChars, prevWordLength, inputCodes, 159 arraySize, (unsigned short*) outputChars, frequencies, outputTypes); 160 } 161 162 if (prevWordChars) { 163 env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); 164 } 165 env->ReleaseIntArrayElements(outputTypesArray, outputTypes, 0); 166 env->ReleaseIntArrayElements(spaceIndexArray, spaceIndices, 0); 167 env->ReleaseCharArrayElements(outputArray, outputChars, 0); 168 env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); 169 env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); 170 env->ReleaseIntArrayElements(pointerIdArray, pointerIds, 0); 171 env->ReleaseIntArrayElements(timesArray, times, 0); 172 env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0); 173 env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0); 174 return count; 175} 176 177static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jobject object, jlong dict, 178 jintArray wordArray, jint wordLength) { 179 Dictionary *dictionary = (Dictionary*)dict; 180 if (!dictionary) return (jboolean) false; 181 jint *word = env->GetIntArrayElements(wordArray, 0); 182 jint result = dictionary->getFrequency(word, wordLength); 183 env->ReleaseIntArrayElements(wordArray, word, JNI_ABORT); 184 return result; 185} 186 187static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject object, jlong dict, 188 jintArray wordArray1, jintArray wordArray2) { 189 Dictionary *dictionary = (Dictionary*)dict; 190 if (!dictionary) return (jboolean) false; 191 jint *word1 = env->GetIntArrayElements(wordArray1, 0); 192 jint *word2 = env->GetIntArrayElements(wordArray2, 0); 193 jsize length1 = word1 ? env->GetArrayLength(wordArray1) : 0; 194 jsize length2 = word2 ? env->GetArrayLength(wordArray2) : 0; 195 jboolean result = dictionary->isValidBigram(word1, length1, word2, length2); 196 env->ReleaseIntArrayElements(wordArray2, word2, JNI_ABORT); 197 env->ReleaseIntArrayElements(wordArray1, word1, JNI_ABORT); 198 return result; 199} 200 201static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object, 202 jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) { 203 jchar *beforeChars = env->GetCharArrayElements(before, 0); 204 jchar *afterChars = env->GetCharArrayElements(after, 0); 205 jfloat result = Correction::RankingAlgorithm::calcNormalizedScore((unsigned short*)beforeChars, 206 beforeLength, (unsigned short*)afterChars, afterLength, score); 207 env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); 208 env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); 209 return result; 210} 211 212static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jobject object, 213 jcharArray before, jint beforeLength, jcharArray after, jint afterLength) { 214 jchar *beforeChars = env->GetCharArrayElements(before, 0); 215 jchar *afterChars = env->GetCharArrayElements(after, 0); 216 jint result = Correction::RankingAlgorithm::editDistance( 217 (unsigned short*)beforeChars, beforeLength, (unsigned short*)afterChars, afterLength); 218 env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); 219 env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); 220 return result; 221} 222 223static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jlong dict) { 224 Dictionary *dictionary = (Dictionary*)dict; 225 if (!dictionary) return; 226 void *dictBuf = dictionary->getDict(); 227 if (!dictBuf) return; 228#ifdef USE_MMAP_FOR_DICTIONARY 229 releaseDictBuf((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), 230 dictionary->getDictSize() + dictionary->getDictBufAdjust(), dictionary->getMmapFd()); 231#else // USE_MMAP_FOR_DICTIONARY 232 releaseDictBuf(dictBuf, 0, 0); 233#endif // USE_MMAP_FOR_DICTIONARY 234 delete dictionary; 235} 236 237void releaseDictBuf(void *dictBuf, const size_t length, int fd) { 238#ifdef USE_MMAP_FOR_DICTIONARY 239 int ret = munmap(dictBuf, length); 240 if (ret != 0) { 241 AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); 242 } 243 ret = close(fd); 244 if (ret != 0) { 245 AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); 246 } 247#else // USE_MMAP_FOR_DICTIONARY 248 free(dictBuf); 249#endif // USE_MMAP_FOR_DICTIONARY 250} 251 252static JNINativeMethod sMethods[] = { 253 {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, 254 {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, 255 {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZ[IZ[C[I[I[I)I", 256 (void*) latinime_BinaryDictionary_getSuggestions}, 257 {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, 258 {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, 259 {"calcNormalizedScoreNative", "([CI[CII)F", 260 (void*)latinime_BinaryDictionary_calcNormalizedScore}, 261 {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} 262}; 263 264int register_BinaryDictionary(JNIEnv *env) { 265 const char *const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; 266 return registerNativeMethods(env, kClassPathName, sMethods, 267 sizeof(sMethods) / sizeof(sMethods[0])); 268} 269} // namespace latinime 270