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