• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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