Home | History | Annotate | Download | only in jni
      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