1 /*
2  * Copyright (C) 2008-2012  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 
17 #include "nj_lib.h"
18 #include "nj_err.h"
19 #include "nj_ext.h"
20 #include "nj_dic.h"
21 #include "njd.h"
22 
23 #define DATA_SIZE (10)
24 #define DATA_OFFSET_FHINSI          (0)
25 #define DATA_OFFSET_BHINSI          (1)
26 #define DATA_OFFSET_HINDO           (2)
27 #define DATA_OFFSET_CANDIDATE       (3)
28 #define DATA_OFFSET_CANDIDATE_LEN   (5)
29 #define DATA_OFFSET_YOMI            (6)
30 #define DATA_OFFSET_YOMI_LEN        (9)
31 
32 #define YOMINASI_DIC_FREQ_DIV 63
33 
34 #define DATA_FHINSI(x)                                                  \
35     ( (NJ_UINT16)(0x01FF &                                              \
36                   (((NJ_UINT16)*((x)+DATA_OFFSET_FHINSI  ) << 1) |      \
37                    (           *((x)+DATA_OFFSET_FHINSI+1) >> 7))) )
38 #define DATA_BHINSI(x)                                                  \
39     ( (NJ_UINT16)(0x01FF &                                              \
40                   (((NJ_UINT16)*((x)+DATA_OFFSET_BHINSI  ) << 2) |      \
41                    (           *((x)+DATA_OFFSET_BHINSI+1) >> 6))) )
42 #define DATA_HINDO(x)                                                   \
43     ((NJ_HINDO)(0x003F & ((NJ_UINT16)*((x)+DATA_OFFSET_HINDO))))
44 #define DATA_CANDIDATE(x)                                               \
45     ((NJ_UINT32)(0x000FFFFF &                                           \
46                  (((NJ_UINT32)*((x)+DATA_OFFSET_CANDIDATE)   << 12) |   \
47                   ((NJ_UINT32)*((x)+DATA_OFFSET_CANDIDATE+1) <<  4) |   \
48                   (           *((x)+DATA_OFFSET_CANDIDATE+2) >>  4))))
49 #define DATA_CANDIDATE_SIZE(x)                                          \
50     ((NJ_UINT8)((*((x)+DATA_OFFSET_CANDIDATE_LEN)   << 4) |             \
51                 (*((x)+DATA_OFFSET_CANDIDATE_LEN+1) >> 4)))
52 #define DATA_YOMI(x) \
53     ((NJ_UINT32)(0x000FFFFF &                                           \
54                  (((NJ_UINT32)*((x)+DATA_OFFSET_YOMI)   << 16) |        \
55                   ((NJ_UINT32)*((x)+DATA_OFFSET_YOMI+1) <<  8) |        \
56                   (           *((x)+DATA_OFFSET_YOMI+2)      ))))
57 #define DATA_YOMI_SIZE(x)                       \
58     ((NJ_UINT8)((*((x)+DATA_OFFSET_YOMI_LEN))))
59 
60 #define YOMI_INDX_TOP_ADDR(h) ((NJ_UINT8*)((h)+NJ_INT32_READ((h)+0x1C)))
61 #define YOMI_INDX_CNT(h) ((NJ_UINT16)(NJ_INT16_READ((h)+0x20)))
62 #define YOMI_INDX_BYTE(h) ((NJ_UINT16)(NJ_INT16_READ((h)+0x22)))
63 #define STEM_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h)+NJ_INT32_READ((h)+0x24)))
64 #define STRS_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h)+NJ_INT32_READ((h)+0x28)))
65 #define YOMI_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h)+NJ_INT32_READ((h)+0x2C)))
66 
67 #define NO_CONV_FLG ((NJ_UINT32) 0x00080000L)
68 
69 #define HINSI_OFFSET (7)
70 
71 #define CURRENT_INFO_SET (NJ_UINT8)(0x10)
72 
73 static NJ_UINT16 search_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset);
74 static NJ_UINT16 convert_to_yomi(NJ_DIC_HANDLE hdl, NJ_UINT8 *index, NJ_UINT16 len, NJ_CHAR *yomi, NJ_UINT16 size);
75 static NJ_UINT16 yomi_strcmp_forward(NJ_DIC_HANDLE hdl, NJ_UINT8 *data, NJ_CHAR *yomi);
76 
search_data(NJ_SEARCH_CONDITION * condition,NJ_SEARCH_LOCATION_SET * loctset)77 static NJ_UINT16 search_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset)
78 {
79     NJ_UINT32 offset;
80     NJ_UINT8 *data;
81     NJ_UINT16 i, j;
82     NJ_UINT16 hindo;
83     NJ_UINT8 hit_flg;
84     NJ_UINT8 *tmp_hinsi = NULL;
85 
86 
87     offset = loctset->loct.current;
88     data = STEM_AREA_TOP_ADDR(loctset->loct.handle) + offset;
89 
90     if (GET_LOCATION_STATUS(loctset->loct.status) != NJ_ST_SEARCH_NO_INIT) {
91         data += DATA_SIZE;
92         offset += DATA_SIZE;
93 
94 
95         if (data >= STRS_AREA_TOP_ADDR(loctset->loct.handle)) {
96 
97             loctset->loct.status = NJ_ST_SEARCH_END;
98             return 0;
99         }
100     }
101 
102 
103     tmp_hinsi = condition->hinsi.fore;
104     condition->hinsi.fore = condition->hinsi.yominasi_fore;
105 
106     i = (NJ_UINT16)((STRS_AREA_TOP_ADDR(loctset->loct.handle) - data) / DATA_SIZE);
107     for (j = 0; j < i; j++) {
108 
109         if (njd_connect_test(condition, DATA_FHINSI(data), DATA_BHINSI(data))) {
110 
111             hit_flg = 0;
112 
113             if (condition->operation == NJ_CUR_OP_LINK) {
114 
115                 hit_flg = 1;
116             } else {
117 
118 
119 
120                 if (yomi_strcmp_forward(loctset->loct.handle, data, condition->yomi)) {
121 
122                     hit_flg = 1;
123                 }
124             }
125 
126             if (hit_flg) {
127 
128                 loctset->loct.current_info = CURRENT_INFO_SET;
129                 loctset->loct.current = offset;
130                 loctset->loct.status = NJ_ST_SEARCH_READY;
131                 hindo = DATA_HINDO(STEM_AREA_TOP_ADDR(loctset->loct.handle) + loctset->loct.current);
132                 loctset->cache_freq = CALCULATE_HINDO(hindo, loctset->dic_freq.base,
133                                                       loctset->dic_freq.high, YOMINASI_DIC_FREQ_DIV);
134 
135 
136                 condition->hinsi.fore = tmp_hinsi;
137                 return 1;
138             }
139         }
140 
141         data += DATA_SIZE;
142         offset += DATA_SIZE;
143     }
144 
145     loctset->loct.status = NJ_ST_SEARCH_END;
146 
147     condition->hinsi.fore = tmp_hinsi;
148     return 0;
149 }
150 
convert_to_yomi(NJ_DIC_HANDLE hdl,NJ_UINT8 * index,NJ_UINT16 len,NJ_CHAR * yomi,NJ_UINT16 size)151 static NJ_UINT16 convert_to_yomi(NJ_DIC_HANDLE hdl, NJ_UINT8 *index, NJ_UINT16 len, NJ_CHAR *yomi, NJ_UINT16 size)
152 {
153     NJ_UINT8  *wkc;
154     NJ_CHAR   *wky;
155     NJ_UINT16 i, idx, yib, ret;
156     NJ_UINT16 j, char_len;
157 
158 
159 
160     wkc = YOMI_INDX_TOP_ADDR(hdl);
161 
162 
163     yib = YOMI_INDX_BYTE(hdl);
164 
165 
166     if (NJ_CHAR_ILLEGAL_DIC_YINDEX(yib)) {
167 
168         return 0;
169     }
170 
171 
172     ret = 0;
173     wky = yomi;
174     for (i = 0; i < len; i++) {
175         idx = (NJ_UINT16)((*index - 1) * yib);
176         if (yib == 2) {
177             char_len = UTL_CHAR(wkc + idx);
178 
179             if (((ret + char_len + NJ_TERM_LEN) * sizeof(NJ_CHAR)) > size) {
180                 return (size / sizeof(NJ_CHAR));
181             }
182             for (j = 0; j < char_len; j++) {
183                 NJ_CHAR_COPY(wky, wkc + idx + j);
184                 wky++;
185                 ret++;
186             }
187         } else {
188 
189             if (((ret + 1 + NJ_TERM_LEN) * sizeof(NJ_CHAR)) > size) {
190                 return (size / sizeof(NJ_CHAR));
191             }
192             *wky++ = (NJ_CHAR)(*(wkc + idx));
193             ret++;
194         }
195         index++;
196     }
197     *wky = NJ_CHAR_NUL;
198     return ret;
199 }
200 
yomi_strcmp_forward(NJ_DIC_HANDLE hdl,NJ_UINT8 * data,NJ_CHAR * yomi)201 static NJ_UINT16 yomi_strcmp_forward(NJ_DIC_HANDLE hdl, NJ_UINT8 *data, NJ_CHAR *yomi)
202 {
203     NJ_UINT8 *area;
204     NJ_CHAR  *stroke;
205     NJ_CHAR   buf[NJ_MAX_LEN + NJ_TERM_LEN];
206     NJ_UINT16 ylen, dic_ylen, j, size;
207 
208 
209 
210     size = sizeof(buf);
211     stroke = buf;
212 
213 
214     area = YOMI_AREA_TOP_ADDR(hdl) + DATA_YOMI(data);
215 
216     if (YOMI_INDX_CNT(hdl) == 0) {
217 
218         dic_ylen = DATA_YOMI_SIZE(data) / sizeof(NJ_CHAR);
219 
220 
221         if (size < ((dic_ylen + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
222             return 0;
223         }
224         for (j = 0; j < dic_ylen; j++) {
225             NJ_CHAR_COPY(stroke, area);
226             stroke++;
227             area += sizeof(NJ_CHAR);
228         }
229         *stroke = NJ_CHAR_NUL;
230     } else {
231 
232         dic_ylen = convert_to_yomi(hdl, area, DATA_YOMI_SIZE(data), stroke, size);
233 
234 
235         if (size < ((dic_ylen + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
236             return 0;
237         }
238     }
239 
240 
241     ylen = nj_strlen(yomi);
242 
243 
244     if (dic_ylen < ylen) {
245 
246         return 0;
247     }
248 
249 
250     if (nj_strncmp(yomi, buf, ylen) == 0) {
251 
252         return 1;
253     }
254     return 0;
255 }
256 
njd_f_search_word(NJ_SEARCH_CONDITION * con,NJ_SEARCH_LOCATION_SET * loctset)257 NJ_INT16 njd_f_search_word(NJ_SEARCH_CONDITION *con, NJ_SEARCH_LOCATION_SET *loctset)
258 {
259     NJ_UINT16 ret;
260 
261     switch (con->operation) {
262     case NJ_CUR_OP_LINK:
263 
264 
265         if ((con->hinsi.yominasi_fore == NULL) ||
266             (con->hinsi.foreSize == 0)) {
267             loctset->loct.status = NJ_ST_SEARCH_END;
268             return 0;
269         }
270         break;
271     case NJ_CUR_OP_FORE:
272 
273 
274         if (NJ_CHAR_STRLEN_IS_0(con->yomi)) {
275             loctset->loct.status = NJ_ST_SEARCH_END;
276             return 0;
277         }
278 
279 
280         if ((con->hinsi.yominasi_fore == NULL) ||
281             (con->hinsi.foreSize == 0)) {
282             loctset->loct.status = NJ_ST_SEARCH_END;
283             return 0;
284         }
285         break;
286     default:
287 
288         loctset->loct.status = NJ_ST_SEARCH_END;
289         return 0;
290     }
291 
292 
293     if (con->mode != NJ_CUR_MODE_FREQ) {
294 
295         loctset->loct.status = NJ_ST_SEARCH_END;
296         return 0;
297     }
298 
299 
300     if ((GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_NO_INIT)
301         || (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_READY)) {
302 
303         ret = search_data(con, loctset);
304         if (ret < 1) {
305 
306             loctset->loct.status = NJ_ST_SEARCH_END;
307         }
308         return ret;
309     } else {
310 
311         loctset->loct.status = NJ_ST_SEARCH_END;
312         return 0;
313     }
314 }
315 
njd_f_get_word(NJ_SEARCH_LOCATION_SET * loctset,NJ_WORD * word)316 NJ_INT16 njd_f_get_word(NJ_SEARCH_LOCATION_SET *loctset, NJ_WORD *word)
317 {
318     NJ_UINT8 *data;
319     NJ_CHAR  stroke[NJ_MAX_LEN + NJ_TERM_LEN];
320     NJ_INT16 yomilen, kouholen;
321 
322 
323 
324     if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_END) {
325         return 0;
326     }
327 
328 
329     data = STEM_AREA_TOP_ADDR(loctset->loct.handle) + loctset->loct.current;
330 
331     NJ_SET_YLEN_TO_STEM(word, 1);
332 
333 
334     word->stem.loc = loctset->loct;
335     yomilen = njd_f_get_stroke(word, stroke, sizeof(stroke));
336     if (yomilen <= 0) {
337         return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_WORD, NJ_ERR_INVALID_RESULT);
338     }
339     word->stem.info1 = yomilen;
340     word->stem.info1 |= (NJ_UINT16)(DATA_FHINSI(data) << HINSI_OFFSET);
341     word->stem.info2 = (NJ_UINT16)(DATA_BHINSI(data) << HINSI_OFFSET);
342     kouholen = (NJ_UINT16)DATA_CANDIDATE_SIZE(data)/sizeof(NJ_CHAR);
343     if (kouholen == 0) {
344 
345         kouholen = yomilen;
346     }
347     word->stem.info2 |= kouholen;
348     word->stem.hindo = CALCULATE_HINDO(DATA_HINDO(data), loctset->dic_freq.base,
349                                        loctset->dic_freq.high, YOMINASI_DIC_FREQ_DIV);
350 
351 
352     word->stem.type = 0;
353 
354     return 1;
355 }
356 
njd_f_get_stroke(NJ_WORD * word,NJ_CHAR * stroke,NJ_UINT16 size)357 NJ_INT16 njd_f_get_stroke(NJ_WORD *word, NJ_CHAR *stroke, NJ_UINT16 size) {
358     NJ_SEARCH_LOCATION *loc;
359     NJ_UINT8 *area, *data;
360     NJ_UINT16 len;
361     NJ_UINT32 j;
362 
363     if (NJ_GET_YLEN_FROM_STEM(word) == 0) {
364         return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_STROKE, NJ_ERR_INVALID_RESULT);
365     }
366 
367 
368 
369     loc = &word->stem.loc;
370     data = STEM_AREA_TOP_ADDR(loc->handle) + loc->current;
371 
372 
373     area = YOMI_AREA_TOP_ADDR(loc->handle) + DATA_YOMI(data);
374 
375     if (YOMI_INDX_CNT(loc->handle) == 0) {
376 
377         len = DATA_YOMI_SIZE(data)/sizeof(NJ_CHAR);
378 
379 
380         if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
381             return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_STROKE, NJ_ERR_BUFFER_NOT_ENOUGH);
382         }
383 
384         for (j = 0; j < len; j++) {
385             NJ_CHAR_COPY(stroke, area);
386             stroke++;
387             area += sizeof(NJ_CHAR);
388         }
389         *stroke = NJ_CHAR_NUL;
390     } else {
391 
392         len = convert_to_yomi(loc->handle, area, DATA_YOMI_SIZE(data), stroke, size);
393 
394 
395         if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
396             return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_STROKE, NJ_ERR_BUFFER_NOT_ENOUGH);
397         }
398     }
399     return len;
400 }
401 
njd_f_get_candidate(NJ_WORD * word,NJ_CHAR * candidate,NJ_UINT16 size)402 NJ_INT16 njd_f_get_candidate(NJ_WORD *word, NJ_CHAR *candidate, NJ_UINT16 size)
403 {
404     NJ_SEARCH_LOCATION *loc;
405     NJ_UINT8 *data, *area;
406     NJ_CHAR   work[NJ_MAX_LEN + NJ_TERM_LEN];
407     NJ_UINT16 len, j;
408 
409 
410 
411 
412     loc = &word->stem.loc;
413     data = STEM_AREA_TOP_ADDR(loc->handle) + loc->current;
414 
415 
416     len = DATA_CANDIDATE_SIZE(data)/sizeof(NJ_CHAR);
417     if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
418         return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_CANDIDATE, NJ_ERR_BUFFER_NOT_ENOUGH);
419     }
420 
421 
422     if (len == 0) {
423 
424         area = YOMI_AREA_TOP_ADDR(loc->handle) + DATA_YOMI(data);
425         if (YOMI_INDX_CNT(loc->handle) == 0) {
426 
427             len = DATA_YOMI_SIZE(data)/sizeof(NJ_CHAR);
428 
429 
430             if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
431                 return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_STROKE, NJ_ERR_BUFFER_NOT_ENOUGH);
432             }
433             for (j = 0; j < len; j++) {
434                 NJ_CHAR_COPY(candidate + j, area);
435                 area += sizeof(NJ_CHAR);
436             }
437             candidate[len] = NJ_CHAR_NUL;
438             return len;
439         } else {
440 
441             len = convert_to_yomi(loc->handle, area, DATA_YOMI_SIZE(data), work, size);
442 
443 
444             if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
445                 return NJ_SET_ERR_VAL(NJ_FUNC_NJD_F_GET_CANDIDATE, NJ_ERR_BUFFER_NOT_ENOUGH);
446             }
447         }
448 
449         if (DATA_CANDIDATE(data) & NO_CONV_FLG) {
450             nje_convert_hira_to_kata(work, candidate, len);
451         } else {
452             for (j = 0; j < len; j++) {
453                 candidate[j] = work[j];
454             }
455         }
456     } else {
457 
458         area = STRS_AREA_TOP_ADDR(loc->handle) + DATA_CANDIDATE(data);
459         for (j = 0; j < len; j++) {
460             NJ_CHAR_COPY(candidate + j, area);
461             area += sizeof(NJ_CHAR);
462         }
463     }
464 
465     candidate[len] = NJ_CHAR_NUL;
466     return len;
467 }
468