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
73static NJ_UINT16 search_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset);
74static NJ_UINT16 convert_to_yomi(NJ_DIC_HANDLE hdl, NJ_UINT8 *index, NJ_UINT16 len, NJ_CHAR *yomi, NJ_UINT16 size);
75static NJ_UINT16 yomi_strcmp_forward(NJ_DIC_HANDLE hdl, NJ_UINT8 *data, NJ_CHAR *yomi);
76
77static 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 = (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
151static 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
201static 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
257NJ_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
316NJ_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
357NJ_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
402NJ_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