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
latinime_BinaryDictionary_open(JNIEnv * env,jobject object,jstring sourceDir,jlong dictOffset,jlong dictSize,jint typedLetterMultiplier,jint fullWordMultiplier,jint maxWordLength,jint maxWords,jint maxAlternatives)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
latinime_BinaryDictionary_getSuggestions(JNIEnv * env,jobject object,jint dict,jint proximityInfo,jintArray xCoordinatesArray,jintArray yCoordinatesArray,jintArray inputArray,jint arraySize,jint flags,jcharArray outputArray,jintArray frequencyArray)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
latinime_BinaryDictionary_getBigrams(JNIEnv * env,jobject object,jint dict,jcharArray prevWordArray,jint prevWordLength,jintArray inputArray,jint inputArraySize,jcharArray outputArray,jintArray frequencyArray,jint maxWordLength,jint maxBigrams,jint maxAlternatives)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
latinime_BinaryDictionary_isValidWord(JNIEnv * env,jobject object,jint dict,jcharArray wordArray,jint wordLength)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
latinime_BinaryDictionary_close(JNIEnv * env,jobject object,jint dict)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
releaseDictBuf(void * dictBuf,const size_t length,int fd)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
register_BinaryDictionary(JNIEnv * env)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