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 "binary_format.h" 21 #include "com_android_inputmethod_latin_BinaryDictionary.h" 22 #include "dictionary.h" 23 #include "jni.h" 24 #include "jni_common.h" 25 #include "proximity_info.h" 26 27 #include <assert.h> 28 #include <errno.h> 29 #include <stdio.h> 30 31 #ifdef USE_MMAP_FOR_DICTIONARY 32 #include <sys/mman.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #else // USE_MMAP_FOR_DICTIONARY 37 #include <stdlib.h> 38 #endif // USE_MMAP_FOR_DICTIONARY 39 40 namespace latinime { 41 42 void releaseDictBuf(void* dictBuf, const size_t length, int fd); 43 44 static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, 45 jstring sourceDir, jlong dictOffset, jlong dictSize, 46 jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, 47 jint maxAlternatives) { 48 PROF_OPEN; 49 PROF_START(66); 50 const char *sourceDirChars = env->GetStringUTFChars(sourceDir, NULL); 51 if (sourceDirChars == NULL) { 52 LOGE("DICT: Can't get sourceDir string"); 53 return 0; 54 } 55 int fd = 0; 56 void *dictBuf = NULL; 57 int adjust = 0; 58 #ifdef USE_MMAP_FOR_DICTIONARY 59 /* mmap version */ 60 fd = open(sourceDirChars, O_RDONLY); 61 if (fd < 0) { 62 LOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 63 return 0; 64 } 65 int pagesize = getpagesize(); 66 adjust = dictOffset % pagesize; 67 int adjDictOffset = dictOffset - adjust; 68 int adjDictSize = dictSize + adjust; 69 dictBuf = mmap(NULL, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); 70 if (dictBuf == MAP_FAILED) { 71 LOGE("DICT: Can't mmap dictionary. errno=%d", errno); 72 return 0; 73 } 74 dictBuf = (void *)((char *)dictBuf + adjust); 75 #else // USE_MMAP_FOR_DICTIONARY 76 /* malloc version */ 77 FILE *file = NULL; 78 file = fopen(sourceDirChars, "rb"); 79 if (file == NULL) { 80 LOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); 81 return 0; 82 } 83 dictBuf = malloc(sizeof(char) * dictSize); 84 if (!dictBuf) { 85 LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); 86 return 0; 87 } 88 int ret = fseek(file, (long)dictOffset, SEEK_SET); 89 if (ret != 0) { 90 LOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno); 91 return 0; 92 } 93 ret = fread(dictBuf, sizeof(char) * dictSize, 1, file); 94 if (ret != 1) { 95 LOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno); 96 return 0; 97 } 98 ret = fclose(file); 99 if (ret != 0) { 100 LOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno); 101 return 0; 102 } 103 #endif // USE_MMAP_FOR_DICTIONARY 104 env->ReleaseStringUTFChars(sourceDir, sourceDirChars); 105 106 if (!dictBuf) { 107 LOGE("DICT: dictBuf is null"); 108 return 0; 109 } 110 Dictionary *dictionary = NULL; 111 if (BinaryFormat::UNKNOWN_FORMAT == BinaryFormat::detectFormat((uint8_t*)dictBuf)) { 112 LOGE("DICT: dictionary format is unknown, bad magic number"); 113 #ifdef USE_MMAP_FOR_DICTIONARY 114 releaseDictBuf(((char*)dictBuf) - adjust, adjDictSize, fd); 115 #else // USE_MMAP_FOR_DICTIONARY 116 releaseDictBuf(dictBuf, 0, 0); 117 #endif // USE_MMAP_FOR_DICTIONARY 118 } else { 119 dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, 120 fullWordMultiplier, maxWordLength, maxWords, maxAlternatives); 121 } 122 PROF_END(66); 123 PROF_CLOSE; 124 return (jint)dictionary; 125 } 126 127 static 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 154 static 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 178 static 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 190 static 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 releaseDictBuf((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), 197 dictionary->getDictSize() + dictionary->getDictBufAdjust(), dictionary->getMmapFd()); 198 #else // USE_MMAP_FOR_DICTIONARY 199 releaseDictBuf(dictBuf, 0, 0); 200 #endif // USE_MMAP_FOR_DICTIONARY 201 delete dictionary; 202 } 203 204 void releaseDictBuf(void* dictBuf, const size_t length, int fd) { 205 #ifdef USE_MMAP_FOR_DICTIONARY 206 int ret = munmap(dictBuf, length); 207 if (ret != 0) { 208 LOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); 209 } 210 ret = close(fd); 211 if (ret != 0) { 212 LOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); 213 } 214 #else // USE_MMAP_FOR_DICTIONARY 215 free(dictBuf); 216 #endif // USE_MMAP_FOR_DICTIONARY 217 } 218 219 static JNINativeMethod sMethods[] = { 220 {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open}, 221 {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, 222 {"getSuggestionsNative", "(II[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, 223 {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, 224 {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams} 225 }; 226 227 int register_BinaryDictionary(JNIEnv *env) { 228 const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary"; 229 return registerNativeMethods(env, kClassPathName, sMethods, 230 sizeof(sMethods) / sizeof(sMethods[0])); 231 } 232 233 } // namespace latinime 234