• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
nativeImOpenDecoder(JNIEnv * env,jclass jclazz,jbyteArray fn_sys_dict,jbyteArray fn_usr_dict)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 
nativeImOpenDecoderFd(JNIEnv * env,jclass jclazz,jobject fd_sys_dict,jlong startoffset,jlong length,jbyteArray fn_usr_dict)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 
nativeImSetMaxLens(JNIEnv * env,jclass jclazz,jint max_sps_len,jint max_hzs_len)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 
nativeImCloseDecoder(JNIEnv * env,jclass jclazz)94 JNIEXPORT jboolean JNICALL nativeImCloseDecoder(JNIEnv* env, jclass jclazz) {
95   im_close_decoder();
96   return JNI_TRUE;
97 }
98 
nativeImSearch(JNIEnv * env,jclass jclazz,jbyteArray pybuf,jint pylen)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 
nativeImDelSearch(JNIEnv * env,jclass jclazz,jint pos,jboolean is_pos_in_splid,jboolean clear_fixed_this_step)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 
nativeImResetSearch(JNIEnv * env,jclass jclazz)119 JNIEXPORT void JNICALL nativeImResetSearch(JNIEnv* env, jclass jclazz) {
120   im_reset_search();
121   return;
122 }
123 
nativeImAddLetter(JNIEnv * env,jclass clazz,jbyte ch)124 JNIEXPORT jint JNICALL nativeImAddLetter(JNIEnv *env, jclass clazz, jbyte ch) {
125   return im_add_letter(ch);
126 }
127 
nativeImGetPyStr(JNIEnv * env,jclass jclazz,jboolean decoded)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 
nativeImGetPyStrLen(JNIEnv * env,jclass jclazz,jboolean decoded)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 
nativeImGetSplStart(JNIEnv * env,jclass jclazz)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 
nativeImGetChoice(JNIEnv * env,jclass clazz,jint candidateId)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 
nativeImChoose(JNIEnv * env,jclass clazz,jint choice_id)190 JNIEXPORT jint JNICALL nativeImChoose(JNIEnv *env, jclass clazz,
191                                       jint choice_id) {
192   return im_choose(choice_id);
193 }
194 
nativeImCancelLastChoice(JNIEnv * env,jclass clazz)195 JNIEXPORT jint JNICALL nativeImCancelLastChoice(JNIEnv *env, jclass clazz) {
196   return im_cancel_last_choice();
197 }
198 
nativeImGetFixedLen(JNIEnv * env,jclass clazz)199 JNIEXPORT jint JNICALL nativeImGetFixedLen(JNIEnv *env, jclass clazz) {
200   return im_get_fixed_len();
201 }
202 
nativeImCancelInput(JNIEnv * env,jclass clazz)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 
nativeImFlushCache(JNIEnv * env,jclass clazz)210 JNIEXPORT jboolean JNICALL nativeImFlushCache(JNIEnv *env, jclass clazz) {
211   im_flush_cache();
212   return JNI_TRUE;
213 }
214 
nativeImGetPredictsNum(JNIEnv * env,jclass clazz,jstring fixed_str)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 
nativeImGetPredictItem(JNIEnv * env,jclass clazz,jint predict_no)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 
nativeSyncBegin(JNIEnv * env,jclass clazz,jbyteArray dict_file)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 
nativeSyncFinish(JNIEnv * env,jclass clazz)262 JNIEXPORT jboolean JNICALL nativeSyncFinish(JNIEnv *env, jclass clazz) {
263   sync_worker.finish();
264   return JNI_TRUE;
265 }
266 
nativeSyncGetCapacity(JNIEnv * env,jclass clazz)267 JNIEXPORT jint JNICALL nativeSyncGetCapacity(JNIEnv *env, jclass clazz) {
268   return sync_worker.get_capacity();
269 }
270 
nativeSyncPutLemmas(JNIEnv * env,jclass clazz,jstring tomerge)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 
nativeSyncGetLemmas(JNIEnv * env,jclass clazz)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 
nativeSyncGetLastCount(JNIEnv * env,jclass clazz)294 JNIEXPORT jint JNICALL nativeSyncGetLastCount(JNIEnv *env, jclass clazz) {
295   return sync_worker.get_last_got_count();
296 }
297 
nativeSyncGetTotalCount(JNIEnv * env,jclass clazz)298 JNIEXPORT jint JNICALL nativeSyncGetTotalCount(JNIEnv *env, jclass clazz) {
299   return sync_worker.get_total_count();
300 }
301 
nativeSyncClearLastGot(JNIEnv * env,jclass clazz)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  */
registerNativeMethods(JNIEnv * env,const char * className,JNINativeMethod * gMethods,int numMethods)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  */
registerNatives(JNIEnv * env)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  */
JNI_OnLoad(JavaVM * vm,void * reserved)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