Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <assert.h>
     18 #include <cutils/log.h>
     19 #include <jni.h>
     20 #include <string.h>
     21 #include <sys/types.h>
     22 #include <unistd.h>
     23 
     24 #include "../include/pinyinime.h"
     25 #include "../include/sync.h"
     26 #include "../include/userdict.h"
     27 
     28 #ifdef __cplusplus
     29 extern "C" {
     30 #endif
     31 
     32 using namespace ime_pinyin;
     33 
     34 #define RET_BUF_LEN 256
     35 
     36 static char16 retbuf[RET_BUF_LEN];
     37 static char16 (*predict_buf)[kMaxPredictSize + 1] = NULL;
     38 static size_t predict_len;
     39 
     40 static Sync sync_worker;
     41 
     42 static struct file_descriptor_offsets_t
     43 {
     44   jclass mClass;
     45   jfieldID mDescriptor;
     46 } gFileDescriptorOffsets;
     47 
     48 JNIEXPORT jboolean JNICALL nativeImOpenDecoder(JNIEnv* env, jclass jclazz,
     49                                                jbyteArray fn_sys_dict,
     50                                                jbyteArray fn_usr_dict) {
     51   jbyte *fsd = (*env).GetByteArrayElements(fn_sys_dict, 0);
     52   jbyte *fud = (*env).GetByteArrayElements(fn_usr_dict, 0);
     53 
     54   jboolean jret = JNI_FALSE;
     55 
     56   if (im_open_decoder((const char*)fsd, (const char*)fud))
     57     jret = JNI_TRUE;
     58 
     59   (*env).ReleaseByteArrayElements(fn_sys_dict, fsd, 0);
     60   (*env).ReleaseByteArrayElements(fn_usr_dict, fud, 0);
     61 
     62   return jret;
     63 }
     64 
     65 JNIEXPORT jboolean JNICALL nativeImOpenDecoderFd(JNIEnv* env, jclass jclazz,
     66                                                  jobject fd_sys_dict,
     67                                                  jlong startoffset,
     68                                                  jlong length,
     69                                                  jbyteArray fn_usr_dict) {
     70   jint fd = env->GetIntField(fd_sys_dict, gFileDescriptorOffsets.mDescriptor);
     71   jbyte *fud = (*env).GetByteArrayElements(fn_usr_dict, 0);
     72 
     73   jboolean jret = JNI_FALSE;
     74 
     75   int newfd = dup(fd);
     76   if (im_open_decoder_fd(newfd, startoffset, length, (const char*)fud))
     77     jret = JNI_TRUE;
     78 
     79   close(newfd);
     80 
     81   (*env).ReleaseByteArrayElements(fn_usr_dict, fud, 0);
     82 
     83   return jret;
     84 }
     85 
     86 JNIEXPORT void JNICALL nativeImSetMaxLens(JNIEnv* env, jclass jclazz,
     87                                           jint max_sps_len,
     88                                           jint max_hzs_len) {
     89   im_set_max_lens(static_cast<size_t>(max_sps_len),
     90                   static_cast<size_t>(max_hzs_len));
     91   return;
     92 }
     93 
     94 JNIEXPORT jboolean JNICALL nativeImCloseDecoder(JNIEnv* env, jclass jclazz) {
     95   im_close_decoder();
     96   return JNI_TRUE;
     97 }
     98 
     99 JNIEXPORT jint JNICALL nativeImSearch(JNIEnv* env, jclass jclazz,
    100                                       jbyteArray pybuf, jint pylen) {
    101   jbyte *array_body = (*env).GetByteArrayElements(pybuf, 0);
    102 
    103   jint jret = 0;
    104   if (NULL != array_body) {
    105     jret = im_search((const char*)array_body, pylen);
    106   }
    107 
    108   (*env).ReleaseByteArrayElements(pybuf, array_body, 0);
    109 
    110   return jret;
    111 }
    112 
    113 JNIEXPORT jint JNICALL nativeImDelSearch(JNIEnv* env, jclass jclazz, jint pos,
    114                                          jboolean is_pos_in_splid,
    115                                          jboolean clear_fixed_this_step) {
    116   return im_delsearch(pos, is_pos_in_splid, clear_fixed_this_step);
    117 }
    118 
    119 JNIEXPORT void JNICALL nativeImResetSearch(JNIEnv* env, jclass jclazz) {
    120   im_reset_search();
    121   return;
    122 }
    123 
    124 JNIEXPORT jint JNICALL nativeImAddLetter(JNIEnv *env, jclass clazz, jbyte ch) {
    125   return im_add_letter(ch);
    126 }
    127 
    128 JNIEXPORT jstring JNICALL nativeImGetPyStr(JNIEnv* env, jclass jclazz,
    129                                            jboolean decoded) {
    130   size_t py_len;
    131   const char *py = im_get_sps_str(&py_len);  // py_len gets decoded length
    132   assert(NULL != py);
    133   if (!decoded)
    134     py_len = strlen(py);
    135 
    136   const unsigned short *spl_start;
    137   size_t len;
    138   len = im_get_spl_start_pos(spl_start);
    139 
    140   size_t i;
    141   for (i = 0; i < py_len; i++)
    142     retbuf[i] = py[i];
    143   retbuf[i] = (char16)'\0';
    144 
    145   jstring retstr = (*env).NewString((unsigned short*)retbuf, i);
    146   return retstr;
    147 }
    148 
    149 JNIEXPORT jint JNICALL nativeImGetPyStrLen(JNIEnv* env, jclass jclazz,
    150                                            jboolean decoded) {
    151   size_t py_len;
    152   const char *py = im_get_sps_str(&py_len);  // py_len gets decoded length
    153   assert(NULL != py);
    154   if (!decoded)
    155     py_len = strlen(py);
    156   return py_len;
    157 }
    158 
    159 JNIEXPORT jintArray JNICALL nativeImGetSplStart(JNIEnv* env, jclass jclazz) {
    160   const unsigned short *spl_start;
    161   size_t len;
    162 
    163   // There will be len + 1 elements in the buffer when len > 0.
    164   len = im_get_spl_start_pos(spl_start);
    165 
    166   jintArray arr = (*env).NewIntArray(len + 2);
    167   jint *arr_body = (*env).GetIntArrayElements(arr, 0);
    168   assert(NULL != arr_body);
    169   arr_body[0] = len; // element 0 is used to store the length of buffer.
    170   for (size_t i = 0; i <= len; i++)
    171     arr_body[i + 1] = spl_start[i];
    172 
    173   (*env).ReleaseIntArrayElements(arr, arr_body, 0);
    174 
    175   return arr;
    176 }
    177 
    178 JNIEXPORT jstring JNICALL nativeImGetChoice(JNIEnv *env, jclass clazz,
    179                                             jint candidateId) {
    180   jstring retstr;
    181   if(im_get_candidate(candidateId, retbuf, RET_BUF_LEN)) {
    182     retstr = (*env).NewString(retbuf, utf16_strlen(retbuf));
    183     return retstr;
    184   } else {
    185     retstr = (*env).NewString((unsigned short*)retbuf, 0);
    186     return retstr;
    187   }
    188 }
    189 
    190 JNIEXPORT jint JNICALL nativeImChoose(JNIEnv *env, jclass clazz,
    191                                       jint choice_id) {
    192   return im_choose(choice_id);
    193 }
    194 
    195 JNIEXPORT jint JNICALL nativeImCancelLastChoice(JNIEnv *env, jclass clazz) {
    196   return im_cancel_last_choice();
    197 }
    198 
    199 JNIEXPORT jint JNICALL nativeImGetFixedLen(JNIEnv *env, jclass clazz) {
    200   return im_get_fixed_len();
    201 }
    202 
    203 JNIEXPORT jboolean JNICALL nativeImCancelInput(JNIEnv *env, jclass clazz) {
    204   if (im_cancel_input())
    205     return JNI_TRUE;
    206 
    207   return JNI_FALSE;
    208 }
    209 
    210 JNIEXPORT jboolean JNICALL nativeImFlushCache(JNIEnv *env, jclass clazz) {
    211   im_flush_cache();
    212   return JNI_TRUE;
    213 }
    214 
    215 JNIEXPORT jint JNICALL nativeImGetPredictsNum(JNIEnv *env, jclass clazz,
    216                                               jstring fixed_str) {
    217   char16 *fixed_ptr = (char16*)(*env).GetStringChars(fixed_str, false);
    218   size_t fixed_len = (size_t)(*env).GetStringLength(fixed_str);
    219 
    220   char16 fixed_buf[kMaxPredictSize + 1];
    221 
    222   if (fixed_len > kMaxPredictSize) {
    223     fixed_ptr += fixed_len - kMaxPredictSize;
    224     fixed_len = kMaxPredictSize;
    225   }
    226   utf16_strncpy(fixed_buf, fixed_ptr, fixed_len);
    227   fixed_buf[fixed_len] = (char16)'\0';
    228 
    229   predict_len = im_get_predicts(fixed_buf, predict_buf);
    230 
    231   (*env).ReleaseStringChars(fixed_str, fixed_ptr);
    232 
    233   return predict_len;
    234 }
    235 
    236 JNIEXPORT jstring JNICALL nativeImGetPredictItem(JNIEnv *env, jclass clazz,
    237                                                  jint predict_no) {
    238   jstring retstr;
    239 
    240   if (predict_no < 0 || (size_t)predict_no >= predict_len) {
    241     retstr = (*env).NewString((unsigned short*)predict_buf[0], 0);
    242   } else {
    243     retstr = (*env).NewString((unsigned short*)predict_buf[predict_no],
    244                               utf16_strlen(predict_buf[predict_no]));
    245   }
    246   return retstr;
    247 }
    248 
    249 JNIEXPORT jboolean JNICALL nativeSyncBegin(JNIEnv *env, jclass clazz,
    250                                            jbyteArray dict_file) {
    251   jbyte *file_name = (*env).GetByteArrayElements(dict_file, 0);
    252 
    253   jboolean jret = JNI_FALSE;
    254   if (true == sync_worker.begin((const char *)file_name))
    255     jret = JNI_TRUE;
    256 
    257   (*env).ReleaseByteArrayElements(dict_file, file_name, 0);
    258 
    259   return jret;
    260 }
    261 
    262 JNIEXPORT jboolean JNICALL nativeSyncFinish(JNIEnv *env, jclass clazz) {
    263   sync_worker.finish();
    264   return JNI_TRUE;
    265 }
    266 
    267 JNIEXPORT jint JNICALL nativeSyncGetCapacity(JNIEnv *env, jclass clazz) {
    268   return sync_worker.get_capacity();
    269 }
    270 
    271 JNIEXPORT jint JNICALL nativeSyncPutLemmas(JNIEnv *env, jclass clazz,
    272                                            jstring tomerge) {
    273 
    274   char16 *ptr = (char16*)(*env).GetStringChars(tomerge, NULL);
    275   int len = (size_t)(*env).GetStringLength(tomerge);
    276 
    277   int added = sync_worker.put_lemmas(ptr, len);
    278 
    279   (*env).ReleaseStringChars(tomerge, ptr);
    280 
    281   return added;
    282 }
    283 
    284 JNIEXPORT jstring JNICALL nativeSyncGetLemmas(JNIEnv *env, jclass clazz) {
    285 
    286   int len = sync_worker.get_lemmas(retbuf, RET_BUF_LEN);
    287   if (len == 0)
    288     return NULL;
    289   jstring retstr;
    290   retstr = (*env).NewString((unsigned short*)retbuf, len);
    291   return retstr;
    292 }
    293 
    294 JNIEXPORT jint JNICALL nativeSyncGetLastCount(JNIEnv *env, jclass clazz) {
    295   return sync_worker.get_last_got_count();
    296 }
    297 
    298 JNIEXPORT jint JNICALL nativeSyncGetTotalCount(JNIEnv *env, jclass clazz) {
    299   return sync_worker.get_total_count();
    300 }
    301 
    302 JNIEXPORT jboolean JNICALL nativeSyncClearLastGot(JNIEnv *env, jclass clazz) {
    303   sync_worker.clear_last_got();
    304   return JNI_TRUE;
    305 }
    306 
    307 /**
    308  * Table of methods associated with a single class.
    309  */
    310 static JNINativeMethod gMethods[] = {
    311     /* name, signature, funcPtr */
    312     /* ------Functions for Pinyin-to-hanzi decoding begin--------->> */
    313     { "nativeImOpenDecoder", "([B[B)Z",
    314             (void*) nativeImOpenDecoder },
    315     { "nativeImOpenDecoderFd", "(Ljava/io/FileDescriptor;JJ[B)Z",
    316             (void*) nativeImOpenDecoderFd },
    317     { "nativeImSetMaxLens", "(II)V",
    318             (void*) nativeImSetMaxLens },
    319     { "nativeImCloseDecoder", "()Z",
    320             (void*) nativeImCloseDecoder },
    321     { "nativeImSearch",  "([BI)I",
    322             (void*) nativeImSearch },
    323     { "nativeImDelSearch",  "(IZZ)I",
    324             (void*) nativeImDelSearch },
    325     { "nativeImResetSearch",  "()V",
    326             (void*) nativeImResetSearch },
    327     { "nativeImAddLetter", "(B)I",
    328             (void*) nativeImAddLetter },
    329     { "nativeImGetPyStr", "(Z)Ljava/lang/String;",
    330             (void*) nativeImGetPyStr },
    331     { "nativeImGetPyStrLen", "(Z)I",
    332             (void*) nativeImGetPyStrLen },
    333     { "nativeImGetSplStart", "()[I",
    334             (void*) nativeImGetSplStart },
    335     { "nativeImGetChoice", "(I)Ljava/lang/String;",
    336             (void*) nativeImGetChoice },
    337     { "nativeImChoose", "(I)I",
    338             (void*) nativeImChoose },
    339     { "nativeImCancelLastChoice", "()I",
    340             (void*) nativeImCancelLastChoice },
    341     { "nativeImGetFixedLen", "()I",
    342             (void*) nativeImGetFixedLen },
    343     { "nativeImGetPredictsNum", "(Ljava/lang/String;)I",
    344             (void*) nativeImGetPredictsNum },
    345     { "nativeImGetPredictItem", "(I)Ljava/lang/String;",
    346             (void*) nativeImGetPredictItem },
    347     { "nativeImCancelInput", "()Z",
    348             (void*) nativeImCancelInput },
    349     { "nativeImFlushCache", "()Z",
    350             (void*) nativeImFlushCache },
    351     /* <<----Functions for Pinyin-to-hanzi decoding end------------- */
    352 
    353     /* ------Functions for sync begin----------------------------->> */
    354     { "nativeSyncBegin", "([B)Z",
    355             (void*) nativeSyncBegin },
    356     { "nativeSyncFinish", "()Z",
    357             (void*) nativeSyncFinish },
    358     { "nativeSyncPutLemmas", "(Ljava/lang/String;)I",
    359             (void*) nativeSyncPutLemmas },
    360     { "nativeSyncGetLemmas", "()Ljava/lang/String;",
    361             (void*) nativeSyncGetLemmas },
    362     { "nativeSyncGetLastCount", "()I",
    363             (void*) nativeSyncGetLastCount },
    364     { "nativeSyncGetTotalCount", "()I",
    365             (void*) nativeSyncGetTotalCount },
    366     { "nativeSyncClearLastGot", "()Z",
    367             (void*) nativeSyncClearLastGot },
    368     { "nativeSyncGetCapacity", "()I",
    369             (void*) nativeSyncGetCapacity },
    370     /* <<----Functions for sync end--------------------------------- */
    371 };
    372 
    373 
    374 /*
    375  * Register several native methods for one class.
    376  */
    377 static int registerNativeMethods(JNIEnv* env, const char* className,
    378     JNINativeMethod* gMethods, int numMethods)
    379 {
    380     jclass clazz;
    381 
    382     clazz = (*env).FindClass(className);
    383     if (clazz == NULL) {
    384         return JNI_FALSE;
    385     }
    386     if ((*env).RegisterNatives(clazz, gMethods, numMethods) < 0) {
    387         return JNI_FALSE;
    388     }
    389 
    390     clazz = env->FindClass("java/io/FileDescriptor");
    391     LOG_FATAL_IF(clazz == NULL, "Unable to find Java class java.io.FileDescriptor");
    392     gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
    393     gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
    394     LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
    395                  "Unable to find descriptor field in java.io.FileDescriptor");
    396 
    397     return JNI_TRUE;
    398 }
    399 
    400 /*
    401  * Register native methods for all classes we know about.
    402  */
    403 static int registerNatives(JNIEnv* env)
    404 {
    405     if (!registerNativeMethods(env,
    406            "com/android/inputmethod/pinyin/PinyinDecoderService",
    407             gMethods, sizeof(gMethods) / sizeof(gMethods[0])))
    408         return JNI_FALSE;
    409 
    410     return JNI_TRUE;
    411 }
    412 
    413 /*
    414  * Set some test stuff up.
    415  *
    416  * Returns the JNI version on success, -1 on failure.
    417  */
    418 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
    419 {
    420     JNIEnv* env = NULL;
    421     jint result = -1;
    422 
    423     if ((*vm).GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
    424         goto bail;
    425     }
    426     assert(env != NULL);
    427 
    428     if (!registerNatives(env)) {
    429         goto bail;
    430     }
    431 
    432     /* success -- return valid version number */
    433     result = JNI_VERSION_1_4;
    434 
    435 bail:
    436     return result;
    437 }
    438 
    439 #ifdef __cplusplus
    440 }
    441 #endif
    442