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