1/*
2 * Copyright (C) 2008,2009  OMRON SOFTWARE Co., Ltd.
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#include "jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni.h"
17
18#include "nj_lib.h"
19#include "nj_err.h"
20#include "nj_ext.h"
21#include "nj_dic.h"
22
23
24#include <stdlib.h>
25#include <string.h>
26#include <dlfcn.h>
27
28#include "OpenWnnJni.h"
29
30
31#include "predef_table.h"
32
33/**
34 * functions for internal use
35 */
36static void clearDictionaryStructure( NJ_DIC_INFO* dicInfo ) {
37	dicInfo->type		= 0;
38	dicInfo->handle		= NULL;
39/*	dicInfo->srhCache	= NULL; */
40
41	dicInfo->dic_freq[ NJ_MODE_TYPE_HENKAN ].base = 0;
42	dicInfo->dic_freq[ NJ_MODE_TYPE_HENKAN ].high = 0;
43}
44
45static NJ_CHAR convertUTFCharToNjChar( NJ_UINT8* src )
46{
47    NJ_CHAR     ret;
48    NJ_UINT8*   dst;
49
50    /* convert UTF-16BE character to NJ_CHAR format */
51    dst = ( NJ_UINT8* )&ret;
52    dst[ 0 ] = src[ 0 ];
53    dst[ 1 ] = src[ 1 ];
54
55    return ret;
56}
57
58static int convertStringToNjChar( JNIEnv *env, NJ_CHAR* dst, jstring srcJ, int maxChars )
59{
60	const unsigned char*	src;
61
62	src = ( const unsigned char* )( ( *env )->GetStringUTFChars( env, srcJ, NULL ) );
63	if( src != NULL ) {
64		int     i, o;
65
66        /* convert UTF-8 to UTF-16BE */
67        for( i = o = 0 ; src[ i ] != 0x00 && o < maxChars ; ) {
68			NJ_UINT8* dst_tmp;
69			dst_tmp = ( NJ_UINT8* )&( dst[ o ] );
70
71            if( ( src[ i ] & 0x80 ) == 0x00 ) {
72                /* U+0000 ... U+007f */
73                /* 8[0xxxxxxx] -> 16BE[00000000 0xxxxxxx] */
74                dst_tmp[ 0 ] = 0x00;
75                dst_tmp[ 1 ] = src[ i + 0 ] & 0x7f;
76                i++;
77                o++;
78            } else if( ( src[ i ] & 0xe0 ) == 0xc0 ) {
79                /* U+0080 ... U+07ff */
80                /* 8[110xxxxx 10yyyyyy] -> 16BE[00000xxx xxyyyyyy] */
81                if( src[ i + 1 ] == 0x00 ) {
82                    break;
83                }
84                dst_tmp[ 0 ] = ( ( src[ i + 0 ] & 0x1f ) >> 2 );
85                dst_tmp[ 1 ] = ( ( src[ i + 0 ] & 0x1f ) << 6 ) |   ( src[ i + 1 ] & 0x3f );
86                i += 2;
87                o++;
88            } else if( ( src[ i ] & 0xf0 ) == 0xe0 ) {
89                /* U+0800 ... U+ffff */
90                /* 8[1110xxxx 10yyyyyy 10zzzzzz] -> 16BE[xxxxyyyy yyzzzzzz] */
91                if( src[ i + 1 ] == 0x00 || src[ i + 2 ] == 0x00 ) {
92                    break;
93                }
94                dst_tmp[ 0 ] = ( ( src[ i + 0 ] & 0x0f ) << 4 ) | ( ( src[ i + 1 ] & 0x3f ) >> 2 );
95                dst_tmp[ 1 ] = ( ( src[ i + 1 ] & 0x3f ) << 6 ) |   ( src[ i + 2 ] & 0x3f );
96                i += 3;
97                o++;
98            } else if( ( src[ i ] & 0xf8 ) == 0xf0 ) {
99                NJ_UINT8    dst1, dst2, dst3;
100                /* U+10000 ... U+10ffff */
101                /* 8[11110www 10xxxxxx 10yyyyyy 10zzzzzz] -> 32BE[00000000 000wwwxx xxxxyyyy yyzzzzzz] */
102                /*                                        -> 16BE[110110WW XXxxxxyy 110111yy yyzzzzzz] */
103                /*                                                      -- --======       == --------  */
104                /*                                                      dst1   dst2          dst3      */
105                /*                                        "wwwxx"(00001-10000) - 1 = "WWXX"(0000-1111) */
106                if( !( o < maxChars - 1 ) ) {
107                    /* output buffer is full */
108                    break;
109                }
110                if( src[ i + 1 ] == 0x00 || src[ i + 2 ] == 0x00 || src[ i + 3 ] == 0x00 ) {
111                    break;
112                }
113                dst1 = ( ( ( src[ i + 0 ] & 0x07 ) << 2 ) | ( ( src[ i + 1 ] & 0x3f ) >> 4 ) ) - 1;
114                dst2 =   ( ( src[ i + 1 ] & 0x3f ) << 4 ) | ( ( src[ i + 2 ] & 0x3f ) >> 2 );
115                dst3 =   ( ( src[ i + 2 ] & 0x3f ) << 6 ) |   ( src[ i + 3 ] & 0x3f );
116
117                dst_tmp[ 0 ] = 0xd8 | ( ( dst1 & 0x0c ) >> 2 );
118                dst_tmp[ 1 ] =        ( ( dst1 & 0x03 ) << 6 ) | ( ( dst2 & 0xfc ) >> 2 );
119                dst_tmp[ 2 ] = 0xdc |                            ( ( dst2 & 0x03 ) );
120                dst_tmp[ 3 ] =                                                              dst3;
121                i += 4;
122                o += 2;
123            } else {    /* Broken code */
124                break;
125            }
126        }
127        dst[ o ] = NJ_CHAR_NUL;
128
129		( *env )->ReleaseStringUTFChars( env, srcJ, ( const char* )src );
130		return 0;
131	}
132	/* If retrieveing the string failed, return an error code */
133	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_CONVERT_STR_TO_NJC, NJ_ERR_JNI_FUNC_FAILED);
134}
135
136static int convertNjCharToString( JNIEnv* env, jstring* dstJ, NJ_CHAR* src, int maxChars )
137{
138    char        dst[ (NJ_MAX_LEN + NJ_MAX_RESULT_LEN + NJ_TERM_LEN ) * 3 + 1 ];
139
140	int		i, o;
141
142	/* convert UTF-16BE to a UTF-8 */
143	for( i = o = 0 ; src[ i ] != 0x0000 && i < maxChars ; ) {
144		NJ_UINT8* src_tmp;
145		src_tmp = ( NJ_UINT8* )&( src[ i ] );
146
147        if( src_tmp[ 0 ] == 0x00 && src_tmp[ 1 ] <= 0x7f ) {
148            /* U+0000 ... U+007f */
149            /* 16BE[00000000 0xxxxxxx] -> 8[0xxxxxxx] */
150            dst[ o + 0 ] = src_tmp[ 1 ] & 0x007f;
151            i++;
152            o++;
153        } else if ( src_tmp[ 0 ] <= 0x07 ) {
154            /* U+0080 ... U+07ff */
155            /* 16BE[00000xxx xxyyyyyy] -> 8[110xxxxx 10yyyyyy] */
156            dst[ o + 0 ] = 0xc0 | ( ( src_tmp[ 0 ] & 0x07 ) << 2 ) | ( ( src_tmp[ 1 ] & 0xc0 ) >> 6 );
157            dst[ o + 1 ] = 0x80 |                                    ( ( src_tmp[ 1 ] & 0x3f ) );
158            i++;
159            o += 2;
160        } else if ( src_tmp[ 0 ] >= 0xd8 && src_tmp[ 0 ] <= 0xdb ) {
161            NJ_UINT8    src1, src2, src3;
162            /* U+10000 ... U+10ffff (surrogate pair) */
163            /* 32BE[00000000 000wwwxx xxxxyyyy yyzzzzzz] -> 8[11110www 10xxxxxx 10yyyyyy 10zzzzzz] */
164            /* 16BE[110110WW XXxxxxyy 110111yy yyzzzzzz]                                           */
165            /*            -- --======       == --------                                            */
166            /*            src1 src2            src3                                                */
167            /* "WWXX"(0000-1111) + 1 = "wwwxx"(0001-10000)                                         */
168            if( !( i < maxChars - 1 ) || src_tmp[ 2 ] < 0xdc || src_tmp[ 2 ] > 0xdf ) {
169                /* That is broken code */
170                break;
171            }
172            src1 = ( ( ( src_tmp[ 0 ] & 0x03 ) << 2 ) | ( ( src_tmp[ 1 ] & 0xc0 ) >> 6 )                               ) + 1;
173            src2 =                                      ( ( src_tmp[ 1 ] & 0x3f ) << 2 ) | ( ( src_tmp[ 2 ] & 0x03 ) );
174            src3 =                                                                             src_tmp[ 3 ];
175
176            dst[ o + 0 ] = 0xf0 | ( ( src1 & 0x1c ) >> 2 );
177            dst[ o + 1 ] = 0x80 | ( ( src1 & 0x03 ) << 4 ) | ( ( src2 & 0xf0 ) >> 4 );
178            dst[ o + 2 ] = 0x80 |                            ( ( src2 & 0x0f ) << 2 ) | ( ( src3 & 0xc0 ) >> 6 );
179            dst[ o + 3 ] = 0x80 |                                                         ( src3 & 0x3f );
180            i += 2;
181            o += 4;
182        } else {
183            /* U+0800 ... U+ffff (except range of surrogate pair) */
184            /* 16BE[xxxxyyyy yyzzzzzz] -> 8[1110xxxx 10yyyyyy 10zzzzzz] */
185            dst[ o + 0 ] = 0xe0 | ( ( src_tmp[ 0 ] & 0xf0 ) >> 4 );
186            dst[ o + 1 ] = 0x80 | ( ( src_tmp[ 0 ] & 0x0f ) << 2 ) | ( ( src_tmp[ 1 ] & 0xc0 ) >> 6  );
187            dst[ o + 2 ] = 0x80 |                                    ( ( src_tmp[ 1 ] & 0x3f ) );
188            i++;
189            o += 3;
190        }
191	}
192	dst[ o ] = 0x00;
193
194	*dstJ = ( *env )->NewStringUTF( env, dst );
195
196	/* If NewString() failed, return an error code */
197	return ( *dstJ == NULL ) ? NJ_SET_ERR_VAL(NJ_FUNC_JNI_CONVERT_NJC_TO_STR, NJ_ERR_JNI_FUNC_FAILED) : 0;
198}
199
200/*
201 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
202 * Method:    createWnnWork
203 * Signature: (Ljava/lang/String;)J
204 */
205JNIEXPORT jlong JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_createWnnWork
206  (JNIEnv *env, jobject obj, jstring dicLibPathJ)
207{
208	NJ_JNIWORK*		work;
209
210	/* Allocating the internal work area */
211	work = ( NJ_JNIWORK* )malloc( sizeof( NJ_JNIWORK ) );
212	if( work != NULL ) {
213		NJ_UINT32*		dic_size;
214		NJ_UINT8*		dic_type;
215        NJ_UINT8**      dic_data;
216        NJ_UINT8**      con_data;
217		const char*		dicLibPath;
218		NJ_INT16		result;
219		int				i;
220
221		/* Initialize the work area */
222		memset( work, 0x00, sizeof( NJ_JNIWORK ) );
223
224		/* Load the dictionary library which is specified by dicLibPathJ */
225		if( dicLibPathJ == NULL ||
226			( dicLibPath = ( *env )->GetStringUTFChars( env, dicLibPathJ, 0 ) ) == NULL ) {
227			free( work );
228			return 0;
229		}
230
231		work->dicLibHandle = ( void* )dlopen( dicLibPath, RTLD_LAZY );
232		( *env )->ReleaseStringUTFChars( env, dicLibPathJ, dicLibPath );
233
234		if( work->dicLibHandle == NULL ) {
235			free( work );
236			return 0;
237		}
238
239		/* Retrieve data pointers of dictionary from the dictionary library, and put to internal work area */
240		dic_size = ( NJ_UINT32* )dlsym( work->dicLibHandle, "dic_size" );
241		dic_type = ( NJ_UINT8* )dlsym( work->dicLibHandle, "dic_type" );
242        dic_data = ( NJ_UINT8** )dlsym( work->dicLibHandle, "dic_data" );
243		if( dic_size == NULL || dic_type == NULL || dic_data == NULL ) {
244			dlclose( work->dicLibHandle );
245			free( work );
246			return 0;
247		}
248
249		for( i = 0 ; i < NJ_MAX_DIC ; i++ ) {
250            work->dicHandle[ i ]    = dic_data[ i ];
251			work->dicSize[ i ]      = dic_size[ i ];
252			work->dicType[ i ]      = dic_type[ i ];
253		}
254
255        /* Set the rule dictionary if the rule data exist */
256        con_data = ( NJ_UINT8** )dlsym( work->dicLibHandle, "con_data" );
257        if( con_data != NULL ) {
258            work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] = con_data[ 0 ];
259        }
260
261		/* Execute the initialize method to initialize the internal work area */
262		result = njx_init( &( work->wnnClass ) );
263
264		if( result >= 0 ) {
265            jlong   jresult;
266
267            *( NJ_JNIWORK** )&jresult = work;
268			return jresult;
269		}
270
271		/* If allocating a byte array failed, free all resource, and return NULL */
272		dlclose( work->dicLibHandle );
273		free( work );
274	}
275	/* If allocating the internal work area failed, return NULL */
276	return 0;
277}
278
279/*
280 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
281 * Method:    freeWnnWork
282 * Signature: (J)I
283 */
284JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_freeWnnWork
285  (JNIEnv *env, jobject obj, jlong wnnWork)
286{
287	NJ_JNIWORK*	work;
288
289	work = *( NJ_JNIWORK** )&wnnWork;
290	if( work != NULL ) {
291		/* If the internal work area was not yet released, remove that */
292        if( work->dicLibHandle != NULL ) {
293        	dlclose( work->dicLibHandle );
294            work->dicLibHandle = NULL;
295        }
296		free( work );
297
298		return 0;
299	}
300
301	/* freeWnnWork() is always successful even if the internal work area was already released */
302	return 0;
303}
304
305/*
306 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
307 * Method:    clearDictionaryParameters
308 * Signature: (J)I
309 */
310JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_clearDictionaryParameters
311  (JNIEnv *env, jobject obj, jlong wnnWork)
312{
313	NJ_JNIWORK*	work;
314
315	work = *( NJ_JNIWORK** )&wnnWork;
316	if( work != NULL ) {
317		int				index;
318
319		/* Clear all dictionary set information structure and reset search state */
320		for( index = 0 ; index < NJ_MAX_DIC ; index++ ) {
321    		clearDictionaryStructure( &( work->dicSet.dic[ index ] ) );
322		}
323        work->flag = NJ_JNI_FLAG_NONE;
324
325        /* Clear the cache information */
326        memset( work->dicSet.keyword, 0x00, sizeof( work->dicSet.keyword ) );
327
328		return 0;
329	}
330
331	/* If the internal work area was already released, return an error code */
332	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_CLEAR_DICTIONARY_PARAMETERS, NJ_ERR_NOT_ALLOCATED);
333}
334
335/*
336 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
337 * Method:    setDictionaryParameter
338 * Signature: (JIII)I
339 */
340JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setDictionaryParameter
341  (JNIEnv *env, jobject obj, jlong wnnWork, jint index, jint base, jint high)
342{
343	NJ_JNIWORK*	work;
344
345	if( ( index < 0  || index > NJ_MAX_DIC-1 ) ||
346		( base <  -1 || base > 1000 ) ||
347		( high <  -1 || high > 1000 ) ) {
348		/* If a invalid parameter was specified, return an error code */
349		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_DICTIONARY_PARAMETERS, NJ_ERR_INVALID_PARAM);
350	}
351
352	work = *( NJ_JNIWORK** )&wnnWork;
353	if( work != NULL ) {
354		/* Create the dictionary set information structure */
355		if( base < 0 || high < 0 || base > high ) {
356			/* If -1 was specified to base or high, clear that dictionary information structure */
357            /* If base is larger than high, clear that dictionary information structure */
358    		clearDictionaryStructure( &( work->dicSet.dic[ index ] ) );
359		} else {
360			/* Set the dictionary informatin structure */
361    		work->dicSet.dic[ index ].type		= work->dicType[ index ];
362    		work->dicSet.dic[ index ].handle	= work->dicHandle[ index ];
363    		work->dicSet.dic[ index ].srhCache	= &( work->srhCache[ index ] );
364
365    		work->dicSet.dic[ index ].dic_freq[ NJ_MODE_TYPE_HENKAN ].base = base;
366    		work->dicSet.dic[ index ].dic_freq[ NJ_MODE_TYPE_HENKAN ].high = high;
367		}
368
369        /* Reset search state because the dicionary information was changed */
370        work->flag = NJ_JNI_FLAG_NONE;
371
372		return 0;
373	}
374
375	/* If the internal work area was already released, return an error code */
376	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_DICTIONARY_PARAMETERS, NJ_ERR_NOT_ALLOCATED);
377}
378
379/*
380 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
381 * Method:    searchWord
382 * Signature: (JIILjava/lang/String;)I
383 */
384JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_searchWord
385  (JNIEnv *env, jobject obj, jlong wnnWork, jint operation, jint order, jstring keyString)
386{
387	NJ_JNIWORK*	work;
388
389	if( !( operation == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_SEARCH_EXACT ||
390           operation == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_SEARCH_PREFIX ||
391           operation == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_SEARCH_LINK ) ||
392		!( order == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_ORDER_BY_FREQUENCY ||
393           order == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_ORDER_BY_KEY ) ||
394		   keyString == NULL ) {
395		/* If a invalid parameter was specified, return an error code */
396		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SEARCH_WORD, NJ_ERR_INVALID_PARAM);
397	}
398
399	work = *( NJ_JNIWORK** )&wnnWork;
400	if( work != NULL ) {
401        if( ( *env )->GetStringLength( env, keyString ) > NJ_MAX_LEN ) {
402            /* If too long key string was specified, return "No result is found" */
403            work->flag &= ~NJ_JNI_FLAG_ENABLE_CURSOR;
404            work->flag &= ~NJ_JNI_FLAG_ENABLE_RESULT;
405            return 0;
406        }
407
408		if( convertStringToNjChar( env, work->keyString, keyString, NJ_MAX_LEN ) >= 0 ) {
409            jint    result;
410
411			/* Set the structure for search */
412			memset( &( work->cursor ), 0x00, sizeof( NJ_CURSOR ) );
413			work->cursor.cond.operation	= operation;
414			work->cursor.cond.mode		= order;
415			work->cursor.cond.ds		= &( work->dicSet );
416			work->cursor.cond.yomi		= work->keyString;
417   			work->cursor.cond.charset	= &( work->approxSet );
418
419            /* If the link search feature is specified, set the predict search information to structure */
420            if( operation == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_SEARCH_LINK ) {
421                work->cursor.cond.yomi  = work->previousStroke;
422                work->cursor.cond.kanji = work->previousCandidate;
423            }
424
425			/* Search a specified word */
426            memcpy( &( work->wnnClass.dic_set ), &( work->dicSet ), sizeof( NJ_DIC_SET ) );
427			result = ( jint )njx_search_word( &( work->wnnClass ), &( work->cursor ) );
428
429            /* If a result is found, enable getNextWord method */
430            if( result == 1 ) {
431                work->flag |= NJ_JNI_FLAG_ENABLE_CURSOR;
432            } else {
433                work->flag &= ~NJ_JNI_FLAG_ENABLE_CURSOR;
434            }
435            work->flag &= ~NJ_JNI_FLAG_ENABLE_RESULT;
436
437            return result;
438		}
439		/* If converting the string failed, return an error code */
440		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SEARCH_WORD, NJ_ERR_INTERNAL);
441	}
442
443	/* If the internal work area was already released, return an error code */
444	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SEARCH_WORD, NJ_ERR_NOT_ALLOCATED);
445}
446
447/*
448 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
449 * Method:    getNextWord
450 * Signature: (JI)I
451 */
452JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getNextWord
453  (JNIEnv *env, jclass obj, jlong wnnWork, jint length)
454{
455	NJ_JNIWORK*	work;
456
457	work = *( NJ_JNIWORK** )&wnnWork;
458	if( work != NULL ) {
459        if( work->flag & NJ_JNI_FLAG_ENABLE_CURSOR ) {
460            jint    result;
461
462       		/* Get a specified word and search a next word */
463            if( length <= 0 ) {
464        		result = ( jint )njx_get_word( &( work->wnnClass ), &( work->cursor ), &( work->result ) );
465            } else {
466                do {
467            		result = ( jint )njx_get_word( &( work->wnnClass ), &( work->cursor ), &( work->result ) );
468                    if( length == ( NJ_GET_YLEN_FROM_STEM( &( work->result.word ) ) + NJ_GET_YLEN_FROM_FZK( &( work->result.word ) ) ) ) {
469                        break;
470                    }
471                } while( result > 0 );
472            }
473
474            /* If a result is found, enable getStroke, getCandidate, getFrequency methods */
475            if( result > 0 ) {
476                work->flag |= NJ_JNI_FLAG_ENABLE_RESULT;
477            } else {
478                work->flag &= ~NJ_JNI_FLAG_ENABLE_RESULT;
479            }
480            return result;
481        } else {
482            /* When njx_search_word() was not yet called, return "No result is found" */
483            return 0;
484        }
485	}
486
487	/* If the internal work area was already released, return an error code */
488	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_WORD, NJ_ERR_NOT_ALLOCATED);
489}
490
491/*
492 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
493 * Method:    getStroke
494 * Signature: (J)Ljava/lang/String;
495 */
496JNIEXPORT jstring JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getStroke
497  (JNIEnv *env, jobject obj, jlong wnnWork)
498{
499	NJ_JNIWORK*	work;
500
501	work = *( NJ_JNIWORK** )&wnnWork;
502	if( work != NULL ) {
503   		jstring		str;
504
505        if( work->flag & NJ_JNI_FLAG_ENABLE_RESULT ) {
506    		NJ_CHAR		stroke[ NJ_MAX_LEN + NJ_TERM_LEN ];
507
508    		if( njx_get_stroke( &( work->wnnClass ), &( work->result ), stroke, sizeof( NJ_CHAR ) * ( NJ_MAX_LEN + NJ_TERM_LEN ) ) >= 0 &&
509    			convertNjCharToString( env, &str, stroke, NJ_MAX_LEN ) >= 0 ) {
510    			return str;
511    		}
512        } else {
513            /* When njx_get_word() was not yet called, return "No result is found" */
514            if( convertNjCharToString( env, &str, ( NJ_CHAR* )"\x00\x00", NJ_MAX_LEN ) >= 0 ) {
515                return str;
516            }
517        }
518	}
519
520	/* If the internal work area was already released, return an error status */
521	return NULL;
522}
523
524/*
525 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
526 * Method:    getCandidate
527 * Signature: (J)Ljava/lang/String;
528 */
529JNIEXPORT jstring JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getCandidate
530  (JNIEnv *env, jobject obj, jlong wnnWork)
531{
532	NJ_JNIWORK*	work;
533
534	work = *( NJ_JNIWORK** )&wnnWork;
535	if( work != NULL ) {
536   		jstring		str;
537
538        if( work->flag & NJ_JNI_FLAG_ENABLE_RESULT ) {
539    		NJ_CHAR		candidate[ NJ_MAX_LEN + NJ_TERM_LEN ];
540
541    		if( njx_get_candidate( &( work->wnnClass ), &( work->result ), candidate, sizeof( NJ_CHAR ) * ( NJ_MAX_RESULT_LEN + NJ_TERM_LEN ) ) >= 0 &&
542    			convertNjCharToString( env, &str, candidate, NJ_MAX_RESULT_LEN ) >= 0 ) {
543    			return str;
544            }
545        } else {
546            /* When njx_get_word() was not yet called, return "No result is found" */
547            if( convertNjCharToString( env, &str, ( NJ_CHAR* )"\x00\x00", NJ_MAX_RESULT_LEN ) >= 0 ) {
548                return str;
549            }
550        }
551	}
552
553	/* If the internal work area was already released, return an error status */
554	return NULL;
555}
556
557/*
558 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
559 * Method:    getFrequency
560 * Signature: (J)I
561 */
562JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getFrequency
563  (JNIEnv *env, jobject obj, jlong wnnWork)
564{
565	NJ_JNIWORK*	work;
566
567	work = *( NJ_JNIWORK** )&wnnWork;
568	if( work != NULL ) {
569        if( work->flag & NJ_JNI_FLAG_ENABLE_RESULT ) {
570    		return ( jint )( work->result.word.stem.hindo );
571        } else {
572            /* When njx_get_word() was not yet called, return "No result is found" */
573            return 0;
574        }
575	}
576
577	/* If the internal work area was already released, return an error code */
578	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_FREQUENCY, NJ_ERR_NOT_ALLOCATED);
579}
580
581/*
582 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
583 * Method:    clearApproxPatterns
584 * Signature: (J)V
585 */
586JNIEXPORT void JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_clearApproxPatterns
587  (JNIEnv *env, jobject obj, jlong wnnWork)
588{
589	NJ_JNIWORK*	work;
590
591	work = *( NJ_JNIWORK** )&wnnWork;
592	if( work != NULL ) {
593		int			i;
594
595        /* Clear state */
596        work->flag = NJ_JNI_FLAG_NONE;
597
598        /* Clear approximate patterns */
599		work->approxSet.charset_count = 0;
600		for( i = 0 ; i < NJ_MAX_CHARSET ; i++ ) {
601			work->approxSet.from[ i ] = NULL;
602			work->approxSet.to[ i ]   = NULL;
603		}
604
605        /* Clear the cache information */
606        memset( work->dicSet.keyword, 0x00, sizeof( work->dicSet.keyword ) );
607	}
608}
609
610/*
611 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
612 * Method:    setApproxPattern
613 * Signature: (JLjava/lang/String;Ljava/lang/String;)I
614 */
615JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setApproxPattern__JLjava_lang_String_2Ljava_lang_String_2
616  (JNIEnv *env, jobject obj, jlong wnnWork, jstring srcJ, jstring dstJ)
617{
618	NJ_JNIWORK*	work;
619
620	if( srcJ == NULL || ( *env )->GetStringLength( env, srcJ ) == 0 || ( *env )->GetStringLength( env, srcJ ) > 1 ||
621		dstJ == NULL || ( *env )->GetStringLength( env, dstJ ) == 0 || ( *env )->GetStringLength( env, dstJ ) > 3 ) {
622		/* If a invalid parameter was specified, return an error code */
623		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_INVALID_PARAM);
624	}
625
626	work = *( NJ_JNIWORK** )&wnnWork;
627	if( work != NULL ) {
628		if( work->approxSet.charset_count < NJ_MAX_CHARSET ) {
629			NJ_CHAR*		from;
630			NJ_CHAR*		to;
631
632			/* Set pointers of string to store approximate informations */
633			from = work->approxStr + NJ_APPROXSTORE_SIZE * work->approxSet.charset_count;
634			to   = work->approxStr + NJ_APPROXSTORE_SIZE * work->approxSet.charset_count + NJ_MAX_CHARSET_FROM_LEN + NJ_TERM_LEN;
635			work->approxSet.from[ work->approxSet.charset_count ] = from;
636			work->approxSet.to[ work->approxSet.charset_count ]   = to;
637
638			/* Convert approximate informations to internal format */
639			if( convertStringToNjChar( env, from, srcJ, NJ_MAX_CHARSET_FROM_LEN ) >= 0 &&
640				convertStringToNjChar( env, to, dstJ, NJ_MAX_CHARSET_TO_LEN )   >= 0 ) {
641				work->approxSet.charset_count++;
642
643                /* Reset search state because the seach condition was changed */
644                work->flag = NJ_JNI_FLAG_NONE;
645
646				return 0;
647			}
648
649			/* If converting informations failed, reset pointers, and return an error code */
650			work->approxSet.from[ work->approxSet.charset_count ] = NULL;
651			work->approxSet.to[ work->approxSet.charset_count ]   = NULL;
652			return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_INTERNAL);
653		}
654		/* If the approx pattern registration area was full, return an error code */
655		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_APPROX_PATTERN_IS_FULL);
656	}
657
658	/* If the internal work area was already released, return an error code */
659	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_NOT_ALLOCATED);
660}
661
662/*
663 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
664 * Method:    setApproxPattern
665 * Signature: (JI)I
666 */
667JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setApproxPattern__JI
668  (JNIEnv *env, jclass obj, jlong wnnWork, jint approxPattern)
669{
670	NJ_JNIWORK	*work;
671
672	if( !( approxPattern == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_APPROX_PATTERN_EN_TOUPPER ||
673		   approxPattern == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_APPROX_PATTERN_EN_TOLOWER ||
674		   approxPattern == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_APPROX_PATTERN_EN_QWERTY_NEAR ||
675		   approxPattern == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_APPROX_PATTERN_EN_QWERTY_NEAR_UPPER ||
676		   approxPattern == jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_APPROX_PATTERN_JAJP_12KEY_NORMAL ) ) {
677		/* If a invalid parameter was specified, return an error code */
678		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_INVALID_PARAM);
679	}
680
681	work = *( NJ_JNIWORK** )&wnnWork;
682	if( work != NULL ) {
683		const PREDEF_APPROX_PATTERN*	pattern;
684
685        pattern = predefinedApproxPatterns[ approxPattern ];
686		if( work->approxSet.charset_count + pattern->size <= NJ_MAX_CHARSET ) {
687			int     i;
688
689			for( i = 0 ; i < pattern->size ; i++ ) {
690				NJ_CHAR*    from;
691				NJ_CHAR*    to;
692
693				/* Set pointers of string to store approximate informations */
694				from = work->approxStr + NJ_APPROXSTORE_SIZE * ( work->approxSet.charset_count + i );
695				to   = work->approxStr + NJ_APPROXSTORE_SIZE * ( work->approxSet.charset_count + i ) + NJ_MAX_CHARSET_FROM_LEN + NJ_TERM_LEN;
696				work->approxSet.from[ work->approxSet.charset_count + i ] = from;
697				work->approxSet.to[ work->approxSet.charset_count + i ]   = to;
698
699				/* Set approximate pattern */
700				from[ 0 ] = convertUTFCharToNjChar( pattern->from + i * 2 );    /* "2" means the size of UTF-16BE */
701				from[ 1 ] = 0x0000;
702
703				to[ 0 ] = convertUTFCharToNjChar( pattern->to + i * 2 );        /* "2" means the size of UTF-16BE */
704				to[ 1 ] = 0x0000;
705			}
706			work->approxSet.charset_count += pattern->size;
707
708            /* Reset search state because the seach condition was changed */
709            work->flag = NJ_JNI_FLAG_NONE;
710
711			return 0;
712		}
713		/* If the approx pattern registration area was full, return an error code */
714		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_APPROX_PATTERN_IS_FULL);
715	}
716
717	/* If the internal work area was already released, return an error code */
718	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_APPROX_PATTERN, NJ_ERR_NOT_ALLOCATED);
719}
720
721/*
722 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
723 * Method:    getLeftPartOfSpeech
724 * Signature: (J)I
725 */
726JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getLeftPartOfSpeech
727  (JNIEnv *env, jclass obj, jlong wnnWork)
728{
729	NJ_JNIWORK*	work;
730
731	work = *( NJ_JNIWORK** )&wnnWork;
732	if( work != NULL ) {
733        return NJ_GET_FPOS_FROM_STEM( &( work->result.word ) );
734    }
735
736	/* If the internal work area was already released, return an error code */
737	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_LEFT_PART_OF_SPEECH, NJ_ERR_NOT_ALLOCATED);
738}
739
740/*
741 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
742 * Method:    getRightPartOfSpeech
743 * Signature: (J)I
744 */
745JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getRightPartOfSpeech
746  (JNIEnv *env, jclass obj, jlong wnnWork)
747{
748	NJ_JNIWORK*	work;
749
750	work = *( NJ_JNIWORK** )&wnnWork;
751	if( work != NULL ) {
752        return NJ_GET_BPOS_FROM_STEM( &( work->result.word ) );
753    }
754
755	/* If the internal work area was already released, return an error code */
756	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_RIGHT_PART_OF_SPEECH, NJ_ERR_NOT_ALLOCATED);
757}
758
759/*
760 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
761 * Method:    clearResult
762 * Signature: (J)V
763 */
764JNIEXPORT void JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_clearResult
765  (JNIEnv *env, jclass obj, jlong wnnWork)
766{
767	NJ_JNIWORK*	work;
768
769	work = *( NJ_JNIWORK** )&wnnWork;
770	if( work != NULL ) {
771        /* Clear the current word information */
772        memset( &( work->result ), 0x00, sizeof( NJ_RESULT ) );
773        memset( &( work->previousStroke ), 0x00, sizeof( work->previousStroke ) );
774        memset( &( work->previousCandidate ), 0x00, sizeof( work->previousCandidate ) );
775    }
776
777    /* In this method, No error reports. */
778}
779
780/*
781 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
782 * Method:    setLeftPartOfSpeech
783 * Signature: (JI)I
784 */
785JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setLeftPartOfSpeech
786  (JNIEnv *env, jclass obj, jlong wnnWork, jint leftPartOfSpeech)
787{
788	NJ_JNIWORK*	work;
789
790	work = *( NJ_JNIWORK** )&wnnWork;
791	if( work != NULL ) {
792        NJ_UINT16   lcount = 0, rcount = 0;
793
794        if( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] == NULL ) {
795            /* No rule dictionary was set */
796        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_LEFT_PART_OF_SPEECH, NJ_ERR_NO_RULEDIC);
797        }
798
799        njd_r_get_count( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], &lcount, &rcount );
800
801        if( leftPartOfSpeech < 1 || leftPartOfSpeech > lcount ) {
802    		/* If a invalid parameter was specified, return an error code */
803    		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_LEFT_PART_OF_SPEECH, NJ_ERR_INVALID_PARAM);
804        }
805
806        NJ_SET_FPOS_TO_STEM( &( work->result.word ), leftPartOfSpeech );
807        return 0;
808    }
809
810	/* If the internal work area was already released, return an error code */
811	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_LEFT_PART_OF_SPEECH, NJ_ERR_NOT_ALLOCATED);
812}
813
814/*
815 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
816 * Method:    setRightPartOfSpeech
817 * Signature: (JI)I
818 */
819JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setRightPartOfSpeech
820  (JNIEnv *env, jclass obj, jlong wnnWork, jint rightPartOfSpeech)
821{
822	NJ_JNIWORK*	work;
823
824	work = *( NJ_JNIWORK** )&wnnWork;
825	if( work != NULL ) {
826        NJ_UINT16   lcount = 0, rcount = 0;
827
828        if( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] == NULL ) {
829            /* No rule dictionary was set */
830        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_RIGHT_PART_OF_SPEECH, NJ_ERR_NO_RULEDIC);
831        }
832
833        njd_r_get_count( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], &lcount, &rcount );
834
835        if( rightPartOfSpeech < 1 || rightPartOfSpeech > rcount ) {
836    		/* If a invalid parameter was specified, return an error code */
837    		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_RIGHT_PART_OF_SPEECH, NJ_ERR_INVALID_PARAM);
838        }
839
840        NJ_SET_BPOS_TO_STEM( &( work->result.word ), rightPartOfSpeech );
841        return 0;
842    }
843
844	/* If the internal work area was already released, return an error code */
845	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_RIGHT_PART_OF_SPEECH, NJ_ERR_NOT_ALLOCATED);
846}
847
848/*
849 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
850 * Method:    setStroke
851 * Signature: (JLjava/lang/String;)I
852 */
853JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setStroke
854  (JNIEnv *env, jclass obj, jlong wnnWork, jstring stroke)
855{
856	NJ_JNIWORK*	work;
857
858    if( stroke == NULL ) {
859		/* If a invalid parameter was specified, return an error code */
860		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_STROKE, NJ_ERR_INVALID_PARAM);
861    }
862
863	work = *( NJ_JNIWORK** )&wnnWork;
864	if( work != NULL ) {
865        if( ( *env )->GetStringLength( env, stroke ) > NJ_MAX_LEN ) {
866    		/* If a invalid parameter was specified, return an error code */
867        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_STROKE, NJ_ERR_YOMI_TOO_LONG);
868        }
869
870        /* Store stroke string */
871		if( convertStringToNjChar( env, work->previousStroke, stroke, NJ_MAX_LEN ) >= 0 ) {
872            return 0;
873        }
874
875		/* If converting the string failed, return an error code */
876		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_STROKE, NJ_ERR_INTERNAL);
877    }
878
879	/* If the internal work area was already released, return an error code */
880	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_STROKE, NJ_ERR_NOT_ALLOCATED);
881}
882
883/*
884 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
885 * Method:    setCandidate
886 * Signature: (JLjava/lang/String;)I
887 */
888JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_setCandidate
889  (JNIEnv *env, jclass obj, jlong wnnWork, jstring candidate)
890{
891	NJ_JNIWORK*	work;
892
893    if( candidate == NULL ) {
894		/* If a invalid parameter was specified, return an error code */
895		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_CANDIDATE, NJ_ERR_INVALID_PARAM);
896    }
897
898	work = *( NJ_JNIWORK** )&wnnWork;
899	if( work != NULL ) {
900        if( ( *env )->GetStringLength( env, candidate ) > NJ_MAX_RESULT_LEN ) {
901    		/* If a invalid parameter was specified, return an error code */
902        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_CANDIDATE, NJ_ERR_CANDIDATE_TOO_LONG);
903        }
904
905        /* Store candidate string */
906		if( convertStringToNjChar( env, work->previousCandidate, candidate, NJ_MAX_RESULT_LEN ) >= 0 ) {
907            return 0;
908        }
909
910		/* If converting the string failed, return an error code */
911		return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_CANDIDATE, NJ_ERR_INTERNAL);
912    }
913
914	/* If the internal work area was already released, return an error code */
915	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SET_CANDIDATE, NJ_ERR_NOT_ALLOCATED);
916}
917
918/*
919 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
920 * Method:    selectWord
921 * Signature: (J)I
922 */
923JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_selectWord
924  (JNIEnv *env, jclass obj, jlong wnnWork)
925{
926	NJ_JNIWORK*	work;
927
928	work = *( NJ_JNIWORK** )&wnnWork;
929	if( work != NULL ) {
930        /* Put the previous word information to engine */
931        memcpy( &( work->wnnClass.dic_set ), &( work->dicSet ), sizeof( NJ_DIC_SET ) );
932        return ( jint )njx_select( &( work->wnnClass ), &( work->result ) );
933    }
934
935	/* If the internal work area was already released, return an error code */
936	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_SELECT_WORD, NJ_ERR_NOT_ALLOCATED);
937}
938
939/*
940 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
941 * Method:    getLeftPartOfSpeechSpecifiedType
942 * Signature: (JI)I
943 */
944JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getLeftPartOfSpeechSpecifiedType
945  (JNIEnv *env, jclass obj, jlong wnnWork, jint type)
946{
947	NJ_JNIWORK*	work;
948
949	work = *( NJ_JNIWORK** )&wnnWork;
950	if( work != NULL ) {
951        switch( type ) {
952        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V1:
953            type = NJ_HINSI_V1_F;
954            break;
955        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V2:
956            type = NJ_HINSI_V2_F;
957            break;
958        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V3:
959            type = NJ_HINSI_V3_F;
960            break;
961        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_BUNTOU:
962    		/* No part of speech is defined at this type */
963            return 0;
964        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_TANKANJI:
965            type = NJ_HINSI_TANKANJI_F;
966            break;
967        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_SUUJI:
968    		/* No part of speech is defined at this type */
969            return 0;
970        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_MEISI:
971            type = NJ_HINSI_MEISI_F;
972            break;
973        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_JINMEI:
974            type = NJ_HINSI_JINMEI_F;
975            break;
976        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_CHIMEI:
977            type = NJ_HINSI_CHIMEI_F;
978            break;
979        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_KIGOU:
980            type = NJ_HINSI_KIGOU_F;
981            break;
982        default:
983    		/* If a invalid parameter was specified, return an error code */
984        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_LEFT_PART_OF_SPEECH_SPECIFIED_TYPE, NJ_ERR_INVALID_PARAM);
985        }
986        return ( jint )njd_r_get_hinsi( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], type );
987    }
988
989	/* If the internal work area was already released, return an error code */
990	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_LEFT_PART_OF_SPEECH_SPECIFIED_TYPE, NJ_ERR_NOT_ALLOCATED);
991}
992
993/*
994 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
995 * Method:    getRightPartOfSpeechSpecifiedType
996 * Signature: (JI)I
997 */
998JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getRightPartOfSpeechSpecifiedType
999  (JNIEnv *env, jclass obj, jlong wnnWork, jint type)
1000{
1001	NJ_JNIWORK*	work;
1002
1003	work = *( NJ_JNIWORK** )&wnnWork;
1004	if( work != NULL ) {
1005        switch( type ) {
1006        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V1:
1007    		/* No part of speech is defined at this type */
1008            return 0;
1009        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V2:
1010    		/* No part of speech is defined at this type */
1011            return 0;
1012        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_V3:
1013    		/* No part of speech is defined at this type */
1014            return 0;
1015        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_BUNTOU:
1016            type = NJ_HINSI_BUNTOU_B;
1017            break;
1018        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_TANKANJI:
1019            type = NJ_HINSI_TANKANJI_B;
1020            break;
1021        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_SUUJI:
1022            type = NJ_HINSI_SUUJI_B;
1023            break;
1024        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_MEISI:
1025            type = NJ_HINSI_MEISI_B;
1026            break;
1027        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_JINMEI:
1028            type = NJ_HINSI_JINMEI_B;
1029            break;
1030        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_CHIMEI:
1031            type = NJ_HINSI_CHIMEI_B;
1032            break;
1033        case jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_POS_TYPE_KIGOU:
1034            type = NJ_HINSI_KIGOU_B;
1035            break;
1036        default:
1037    		/* If a invalid parameter was specified, return an error code */
1038        	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_LEFT_PART_OF_SPEECH_SPECIFIED_TYPE, NJ_ERR_INVALID_PARAM);
1039        }
1040        return ( jint )njd_r_get_hinsi( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], type );
1041    }
1042
1043	/* If the internal work area was already released, return an error code */
1044	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_RIGHT_PART_OF_SPEECH_SPECIFIED_TYPE, NJ_ERR_NOT_ALLOCATED);
1045}
1046
1047/*
1048 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1049 * Method:    getConnectArray
1050 * Signature: (JI)[B
1051 */
1052JNIEXPORT jbyteArray JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getConnectArray
1053  (JNIEnv *env, jclass obj, jlong wnnWork, jint leftPartOfSpeech)
1054{
1055	NJ_JNIWORK*	work;
1056
1057	work = *( NJ_JNIWORK** )&wnnWork;
1058	if( work != NULL ) {
1059        NJ_UINT16   lcount = 0, rcount = 0;
1060        jbyteArray  resultJ;
1061
1062        if( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] == NULL ) {
1063            /* No rule dictionary was set */
1064        	return NULL;
1065        }
1066
1067        njd_r_get_count( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], &lcount, &rcount );
1068
1069        if( leftPartOfSpeech < 0 || leftPartOfSpeech > lcount ) {
1070            /* Invalid POS is specified */
1071            return NULL;
1072        }
1073
1074        /* 1-origin */
1075        resultJ = ( *env )->NewByteArray( env, rcount + 1 );
1076
1077        if( resultJ != NULL ) {
1078            jbyte   *result;
1079            result = ( *env )->GetByteArrayElements( env, resultJ, NULL );
1080
1081            if( result != NULL ) {
1082                int         i;
1083                NJ_UINT8*   connect;
1084
1085                if( leftPartOfSpeech == 0 ) {
1086                    for( i = 0 ; i < rcount + 1 ; i++ ) {
1087                        result[ i ] = 0;
1088                    }
1089                } else {
1090                    /* Get the packed connect array */
1091                    njd_r_get_connect( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], leftPartOfSpeech, NJ_RULE_TYPE_FTOB, &connect );
1092
1093                    /* Extract connect array from bit field */
1094                    result[ 0 ] = 0;
1095
1096                    for( i = 0 ; i < rcount ; i++ ) {
1097                        if( connect[ i / 8 ] & (0x80 >> (i % 8))) {
1098                            result[ i + 1 ] = 1;
1099                        } else {
1100                            result[ i + 1 ] = 0;
1101                        }
1102                    }
1103                }
1104
1105                ( *env )->ReleaseByteArrayElements( env, resultJ, result, 0 );
1106                return resultJ;
1107            }
1108        }
1109		/* If allocating the return area failed, return an error code */
1110       	return NULL;
1111    }
1112	/* If the internal work area was already released, return an error code */
1113    return NULL;
1114}
1115
1116/*
1117 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1118 * Method:    getNumberOfLeftPOS
1119 * Signature: (J)I
1120 */
1121JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getNumberOfLeftPOS
1122  (JNIEnv *env, jclass obj, jlong wnnWork)
1123{
1124	NJ_JNIWORK*	work;
1125
1126	work = *( NJ_JNIWORK** )&wnnWork;
1127	if( work != NULL ) {
1128        if( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] == NULL ) {
1129            /* No rule dictionary was set */
1130            return 0;
1131        } else {
1132            NJ_UINT16   lcount = 0, rcount = 0;
1133
1134            njd_r_get_count( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], &lcount, &rcount );
1135            return lcount;
1136        }
1137    }
1138
1139	/* If the internal work area was already released, return an error code */
1140	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_NUMBER_OF_LEFT_POS, NJ_ERR_NOT_ALLOCATED);
1141}
1142
1143/*
1144 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1145 * Method:    getNumberOfRightPOS
1146 * Signature: (J)I
1147 */
1148JNIEXPORT jint JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getNumberOfRightPOS
1149  (JNIEnv *env, jclass obj, jlong wnnWork)
1150{
1151	NJ_JNIWORK*	work;
1152
1153	work = *( NJ_JNIWORK** )&wnnWork;
1154	if( work != NULL ) {
1155        if( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ] == NULL ) {
1156            /* No rule dictionary was set */
1157            return 0;
1158        } else {
1159            NJ_UINT16   lcount = 0, rcount = 0;
1160
1161            njd_r_get_count( work->dicSet.rHandle[ NJ_MODE_TYPE_HENKAN ], &lcount, &rcount );
1162            return rcount;
1163        }
1164    }
1165
1166	/* If the internal work area was already released, return an error code */
1167	return NJ_SET_ERR_VAL(NJ_FUNC_JNI_GET_NUMBER_OF_RIGHT_POS, NJ_ERR_NOT_ALLOCATED);
1168}
1169
1170/*
1171 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1172 * Method:    getApproxPattern
1173 * Signature: (JLjava/lang/String;)[Ljava/lang/String;
1174 */
1175JNIEXPORT jobjectArray JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_getApproxPattern
1176  (JNIEnv *env, jclass obj, jlong wnnWork, jstring srcJ)
1177{
1178	NJ_JNIWORK*	work;
1179
1180	if( srcJ == NULL || ( *env )->GetStringLength( env, srcJ ) == 0 || ( *env )->GetStringLength( env, srcJ ) > 1 ) {
1181		/* If a invalid parameter was specified, return an error code */
1182		return NULL;
1183	}
1184
1185	work = *( NJ_JNIWORK** )&wnnWork;
1186	if( work != NULL ) {
1187        int         i, outIndex, outCount;
1188        NJ_CHAR     from[ NJ_MAX_CHARSET_FROM_LEN + NJ_TERM_LEN ];
1189
1190        if( convertStringToNjChar( env, from, srcJ, NJ_MAX_CHARSET_FROM_LEN ) >= 0 ) {
1191            outCount = 0;
1192            for( i = 0 ; i < work->approxSet.charset_count ; i++ ) {
1193                if( nj_strcmp( from, work->approxSet.from[ i ] ) == 0 ) {
1194                    outCount++;
1195                }
1196            }
1197
1198            jclass strC = ( *env )->FindClass( env, "java/lang/String" );
1199
1200            if( strC != NULL ) {
1201                jobjectArray retJ = ( *env )->NewObjectArray( env, outCount, strC, NULL );
1202
1203                if( retJ != NULL ) {
1204                    for( i = outIndex = 0 ; i < work->approxSet.charset_count ; i++ ) {
1205                        if( nj_strcmp( from, work->approxSet.from[ i ] ) == 0 ) {
1206                            jstring dstJ;
1207
1208                            if( convertNjCharToString( env, &dstJ, work->approxSet.to[ i ], NJ_MAX_CHARSET_TO_LEN ) < 0 ) {
1209                                return NULL;
1210                            }
1211
1212                            ( *env )->SetObjectArrayElement( env, retJ, outIndex++, dstJ );
1213                        }
1214
1215                    }
1216                    return retJ;
1217                }
1218            }
1219        }
1220        /* If the internal error occured, return an error code */
1221        return NULL;
1222    }
1223
1224	/* If the internal work area was already released, return an error code */
1225	return NULL;
1226}
1227
1228/*
1229 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1230 * Method:    createBindArray
1231 * Signature: (JLjava/lang/String;II)[Ljava/lang/String;
1232 */
1233JNIEXPORT jobjectArray JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_createBindArray
1234  (JNIEnv *env, jclass obj, jlong wnnWork, jstring keyStringJ, jint maxBindsOfQuery, jint maxPatternOfApprox)
1235{
1236	NJ_JNIWORK*	work;
1237
1238	if( keyStringJ == NULL ) {
1239		/* If a invalid parameter was specified, return an error code */
1240		return NULL;
1241	}
1242
1243	work = *( NJ_JNIWORK** )&wnnWork;
1244	if( work != NULL ) {
1245        /* create the string array for result */
1246        jclass strC = ( *env )->FindClass( env, "java/lang/String" );
1247
1248        if( strC != NULL ) {
1249            jobjectArray retJ = ( *env )->NewObjectArray( env, maxBindsOfQuery * (maxPatternOfApprox+1), strC, NULL );
1250
1251            if( retJ != NULL ) {
1252                NJ_CHAR     keyString[ NJ_MAX_LEN + NJ_TERM_LEN ];
1253
1254                if( convertStringToNjChar( env, keyString, keyStringJ, NJ_MAX_LEN ) >= 0 ) {
1255                    int         queryLen, outIndex, approxPattern;
1256                    NJ_CHAR     baseStr[ NJ_MAX_LEN + NJ_MAX_CHARSET_TO_LEN + NJ_TERM_LEN ];
1257
1258                    outIndex = 0;
1259                    baseStr[ 0 ] = NJ_CHAR_NUL;
1260
1261                    for( queryLen = 0 ; queryLen < maxBindsOfQuery && keyString[ queryLen ] != NJ_CHAR_NUL ; queryLen++ ) {
1262                        int i;
1263
1264                        for( i = -1, approxPattern = -1 ; i < work->approxSet.charset_count ; i++ ) {
1265                            if( i == -1 || keyString[ queryLen ] == work->approxSet.from[ i ][ 0 ] ) {
1266                                int tailOffset = 0;
1267
1268                                if( i == -1 ) {
1269                                    if(   *( ( NJ_UINT8* )( &keyString[ queryLen ] ) + 0 ) == 0x00 &&
1270                                        ( *( ( NJ_UINT8* )( &keyString[ queryLen ] ) + 1 ) == 0x25 ||       /* '%' */
1271                                          *( ( NJ_UINT8* )( &keyString[ queryLen ] ) + 1 ) == 0x5c ||       /* '\' */
1272                                          *( ( NJ_UINT8* )( &keyString[ queryLen ] ) + 1 ) == 0x5f ) ) {    /* '_' */
1273                                        *( ( NJ_UINT8* )( &baseStr[ queryLen + 0 ] ) + 0 ) = 0x00;
1274                                        *( ( NJ_UINT8* )( &baseStr[ queryLen + 0 ] ) + 1 ) = 0x5c;  /* '\' */
1275                                                           baseStr[ queryLen + 1 ] = keyString[ queryLen ];
1276                                        tailOffset = 2;
1277                                    } else {
1278                                        baseStr[ queryLen + 0 ] = keyString[ queryLen ];
1279                                        tailOffset = 1;
1280                                    }
1281                                } else {
1282                                    nj_strcpy( &baseStr[ queryLen ], work->approxSet.to[ i ] );
1283                                    tailOffset = nj_strlen( work->approxSet.to[ i ] );
1284                                }
1285
1286                                *( ( NJ_UINT8* )( &baseStr[ queryLen + tailOffset     ] ) + 0 ) = 0x00;
1287                                *( ( NJ_UINT8* )( &baseStr[ queryLen + tailOffset     ] ) + 1 ) = 0x25;  /* '%' */
1288                                                   baseStr[ queryLen + tailOffset + 1 ]         = NJ_CHAR_NUL;
1289
1290                                jstring dstJ;
1291                                if( convertNjCharToString( env, &dstJ, baseStr, NJ_MAX_LEN ) < 0 ) {
1292                                    return NULL;
1293                                }
1294
1295                                ( *env )->SetObjectArrayElement( env, retJ, outIndex++, dstJ );
1296                                approxPattern++;
1297                            }
1298                        }
1299                        for( ; approxPattern < maxPatternOfApprox ; approxPattern++ ) {
1300                            jstring dstJ = ( *env )->NewStringUTF( env, "" );
1301                            if( dstJ == NULL ) {
1302                                return NULL;
1303                            }
1304                            ( *env )->SetObjectArrayElement( env, retJ, outIndex++, dstJ );
1305                        }
1306
1307                        *( ( NJ_UINT8* )( &baseStr[ queryLen     ] ) + 0 ) = 0x00;
1308                        *( ( NJ_UINT8* )( &baseStr[ queryLen     ] ) + 1 ) = 0x5f;  /* '_' */
1309                                           baseStr[ queryLen + 1 ]         = NJ_CHAR_NUL;
1310                    }
1311
1312                    for( ; queryLen < maxBindsOfQuery ; queryLen++ ) {
1313                        for( approxPattern = -1 ; approxPattern < maxPatternOfApprox ; approxPattern++ ) {
1314                            jstring dstJ = ( *env )->NewStringUTF( env, "%" );
1315                            if( dstJ == NULL ) {
1316                                return NULL;
1317                            }
1318                            ( *env )->SetObjectArrayElement( env, retJ, outIndex++, dstJ );
1319                        }
1320                    }
1321
1322                    return retJ;
1323                }
1324            }
1325        }
1326        /* If the internal error occured, return an error code */
1327        return NULL;
1328    }
1329
1330	/* If the internal work area was already released, return an error code */
1331	return NULL;
1332}
1333
1334/*
1335 * Class:     jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni
1336 * Method:    createQueryStringBase
1337 * Signature: (JIILjava/lang/String;)Ljava/lang/String;
1338 */
1339JNIEXPORT jstring JNICALL Java_jp_co_omronsoft_openwnn_OpenWnnDictionaryImplJni_createQueryStringBase
1340  (JNIEnv *env, jclass obj, jlong wnnWork, jint maxBindsOfQuery, jint maxPatternOfApprox, jstring keyColumnNameJ)
1341{
1342    NJ_JNIWORK*	work;
1343    jstring retJ = NULL;
1344
1345	if( keyColumnNameJ == NULL ) {
1346		/* If a invalid parameter was specified, return an error code */
1347		return NULL;
1348	}
1349
1350	work = *( NJ_JNIWORK** )&wnnWork;
1351	if( work != NULL ) {
1352    	const unsigned char* keyName = ( const unsigned char* )( ( *env )->GetStringUTFChars( env, keyColumnNameJ, NULL ) );
1353
1354        if( keyName != NULL ) {
1355            int keyLength = strlen( ( char* )keyName );
1356
1357            char *dst = ( char* )malloc( maxBindsOfQuery * ( ( 1 + keyLength + 18 + 1 + 5 ) +
1358                                                             ( ( 4 + keyLength + 18 ) * maxPatternOfApprox ) +
1359                                                             1 ) );
1360            if( dst != NULL ) {
1361                int queryLen, dstPtr;
1362
1363            	for( queryLen = dstPtr = 0 ; queryLen < maxBindsOfQuery ; queryLen++ ) {
1364                    int approxPattern;
1365
1366                    strcpy( &dst[ dstPtr                 ], "(" );
1367                    strcpy( &dst[ dstPtr + 1             ], ( char* )keyName );
1368                    strcpy( &dst[ dstPtr + 1 + keyLength ], " like ? escape '\x5c'" );
1369                    dstPtr += 1 + keyLength + 18;
1370
1371            		for( approxPattern = 0 ; approxPattern < maxPatternOfApprox ; approxPattern++ ) {
1372                        strcpy( &dst[ dstPtr                 ], " or " );
1373                        strcpy( &dst[ dstPtr + 4             ], ( char* )keyName );
1374                        strcpy( &dst[ dstPtr + 4 + keyLength ], " like ? escape '\x5c'" );
1375                        dstPtr += 4 + keyLength + 18;
1376            		}
1377                    strcpy( &dst[ dstPtr ], ")" );
1378                    dstPtr++;
1379
1380            		if( queryLen != maxBindsOfQuery-1 ) {
1381                        strcpy( &dst[ dstPtr ], " and " );
1382                        dstPtr += 5;
1383            		}
1384            	}
1385
1386                dst[ dstPtr ] = '\0';
1387                retJ = ( *env )->NewStringUTF( env, dst );
1388
1389                free( dst );
1390            }
1391
1392       		( *env )->ReleaseStringUTFChars( env, keyColumnNameJ, ( const char* )keyName );
1393        }
1394    }
1395	return retJ;
1396}
1397
1398