text: /*
   * Copyright (C) 2008,2009  OMRON SOFTWARE Co., Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #include "nj_lib.h"
  #include "nj_err.h"
  #include "nj_ext.h"
  #include "nj_dic.h"
  #include "njd.h"
  
  #define NODE_TERM(x) ((NJ_UINT8)(0x80 & (*(x))))
  #define NODE_LEFT_EXIST(x) ((NJ_UINT8)(0x40 & (*(x))))
  #define NODE_DATA_EXIST(x) ((NJ_UINT8)(0x20 & (*(x))))
  #define NODE_IDX_EXIST(x) ((NJ_UINT8)(0x10 & (*(x))))
  #define NODE_IDX_CNT(x) ((NJ_UINT8)((0x0f & (*(x))) + 2))
  
  #define STEM_TERMINETER(x) ((NJ_UINT8)(0x80 & (*(x))))
  
  #define STEM_NO_CONV_FLG(x) ((NJ_UINT8)(0x40 & (*(x))))
  
  #define TERM_BIT (1)
  #define INDEX_BIT (8)
  
  #define APPEND_YOMI_FLG(h) ((NJ_UINT8)(0x80 & (*((h) + 0x1C))))
  #define HINSI_NO_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x1D)))
  #define FHINSI_NO_CNT(h) ((NJ_INT16)(NJ_INT16_READ((h) + 0x21)))
  #define BHINSI_NO_CNT(h) ((NJ_INT16)(NJ_INT16_READ((h) + 0x23)))
  #define HINSI_NO_BYTE(h) ((NJ_UINT8)(*((h) + 0x25)))
  #define HINDO_NO_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x26)))
  #define HINDO_NO_CNT(h) ((NJ_UINT8)(*((h) + 0x2A)))
  #define STEM_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x2B)))
  #define BIT_CANDIDATE_LEN(h) ((NJ_UINT8)(*((h) + 0x2F)))
  #define BIT_FHINSI(h) ((NJ_UINT8)(*((h) + 0x30)))
  #define BIT_BHINSI(h) ((NJ_UINT8)(*((h) + 0x31)))
  #define BIT_HINDO_LEN(h) ((NJ_UINT8)(*((h) + 0x32)))
  #define BIT_MUHENKAN_LEN(h) ((NJ_UINT8)(*((h) + 0x33)))
  #define BIT_YOMI_LEN(h) ((NJ_UINT8)(*((h) + 0x35)))
  #define YOMI_INDX_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x42)))
  #define YOMI_INDX_CNT(h) ((NJ_INT16)(*((h) + 0x46)))
  #define YOMI_INDX_SIZE(h) ((NJ_INT8)(*((h) + 0x47)))
  #define NODE_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x48)))
  #define BIT_NODE_AREA_DATA_LEN(h) ((NJ_UINT8)(*((h) + 0x4C)))
  #define BIT_NODE_AREA_LEFT_LEN(h) ((NJ_UINT8)(*((h) + 0x4D)))
  #define NODE_AREA_MID_ADDR(h) ((NJ_UINT32)(NJ_INT32_READ((h) + 0x4E)))
  #define CAND_IDX_AREA_TOP_ADDR(h) ((NJ_UINT8*)((h) + NJ_INT32_READ((h) + 0x52)))
  #define CAND_IDX_AREA_CNT(h) ((NJ_UINT32)(((NJ_INT32_READ((h) + 0x56)) >> 8) & 0x00FFFFFF))
  #define CAND_IDX_AREA_SIZE(h) ((NJ_UINT8)(*((h) + 0x59)))
  
  #define WORD_LEN(x) ((NJ_UINT16)(0x007F & (x)))
  
  #define CURRENT_INFO_SET ((NJ_UINT8)(0x10))
  
  #define COMP_DIC_FREQ_DIV 63
  
  #define LOC_CURRENT_NO_ENTRY  0xffffffffU
  
  typedef struct {
      NJ_UINT16 stem_size;
      NJ_UINT16 term;
      NJ_UINT16 no_conv_flg;
      NJ_HINDO hindo;
      NJ_UINT16 hindo_jitu;
      NJ_UINT16 candidate_size;
      NJ_UINT16 yomi_size;
      NJ_UINT16 fhinsi;
      NJ_UINT16 bhinsi;
      NJ_UINT16 fhinsi_jitu;
      NJ_UINT16 bhinsi_jitu;
  } STEM_DATA_SET;
  
  static NJ_INT16 get_stem_next(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data);
  static void get_stem_word(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, STEM_DATA_SET *stem_set, NJ_UINT8 check);
  static void get_stem_cand_data(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, STEM_DATA_SET *stem_set);
  static NJ_UINT16 get_stem_yomi_data(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data,STEM_DATA_SET *stem_set);
  static NJ_UINT16 get_stem_yomi_size(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, NJ_UINT16 yomi_size);
  static NJ_UINT16 get_stem_yomi_string(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, NJ_CHAR *yomi, NJ_UINT16 yomi_pos, NJ_UINT16 yomi_size, NJ_UINT16 size);
  static NJ_INT16 search_node(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset);
  static NJ_INT16 bdic_search_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset);
  static NJ_INT16 bdic_search_fore_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset);
  
  static NJ_HINDO get_stem_hindo(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data);
  
  static NJ_INT16 search_node2(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset,
                               NJ_UINT16 hidx);
  static NJ_INT16 bdic_search_fore_data2(NJ_SEARCH_CONDITION *condition,
                                         NJ_SEARCH_LOCATION_SET *loctset, NJ_UINT16 hidx);
  static NJ_INT16 search_yomi_node(NJ_UINT8 operation, NJ_UINT8 *node,
                                   NJ_UINT8 *now, NJ_UINT16 idx_no,
                                   NJ_CHAR  *yomi, NJ_UINT16 yomilen,
                                   NJ_UINT8 *root, NJ_UINT8 *node_mid,
                                   NJ_UINT16 bit_left, NJ_UINT16 bit_data,
                                   NJ_UINT8 *data_top,
                                   NJ_INT16 ytbl_cnt, NJ_UINT16 y,
                                   NJ_UINT8 *ytbl_top, NJ_CACHE_INFO *storebuf,
                                   NJ_UINT8 **con_node, NJ_UINT32 *data_offset);
  static NJ_INT16 get_node_bottom(NJ_CHAR *yomi, NJ_UINT8 *now, NJ_UINT8 *node_mid,
                                  NJ_UINT8 *data_top, NJ_UINT16 bit_left,
                                  NJ_UINT16 bit_data, NJ_UINT32 top,
                                  NJ_DIC_HANDLE handle, NJ_UINT32 *ret_bottom);
  static NJ_INT16 bdic_get_next_data(NJ_UINT8 *data_top, NJ_UINT8 *data_end,
                                     NJ_SEARCH_LOCATION_SET *loctset,
                                     NJ_SEARCH_CACHE *psrhCache, NJ_UINT16 abIdx);
  static NJ_INT16 bdic_get_word_freq(NJ_UINT8 *data_top, NJ_SEARCH_LOCATION_SET *loctset,
                                     NJ_SEARCH_CACHE *psrhCache, NJ_UINT16 abIdx);
  
  static NJ_HINDO get_stem_hindo(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data)
  {
      NJ_UINT8 flg_bit;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all;
  
      flg_bit = BIT_MUHENKAN_LEN(hdl);
      if (NJ_GET_DIC_FMT(hdl) != NJ_DIC_FMT_KANAKAN) {
          flg_bit++;
      }
  
      if (BIT_HINDO_LEN(hdl)) {
  
          bit_all = (NJ_UINT16)(TERM_BIT + flg_bit);
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
          j = (NJ_UINT16)(bit_all & 0x0007);
  
          return GET_BITFIELD_16(data, j, BIT_HINDO_LEN(hdl));
      } else {
          return 0;
      }
  }
  
  static NJ_INT16 get_stem_next(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data)
  {
      NJ_UINT8 flg_bit;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all;
      NJ_UINT16 stem_size, cand_bit, yomi_bit;
      NJ_UINT16 candidate_size, yomi_size;
  
      flg_bit = BIT_MUHENKAN_LEN(hdl);
      if (NJ_GET_DIC_FMT(hdl) != NJ_DIC_FMT_KANAKAN) {
          flg_bit++;
      }
  
      bit_all = (NJ_UINT16)(TERM_BIT + flg_bit +
                            BIT_HINDO_LEN(hdl) +
                            BIT_FHINSI(hdl) +
                            BIT_BHINSI(hdl));
      pos = (NJ_UINT16)(bit_all >> 3);
      data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
      j = (NJ_UINT16)(bit_all & 0x0007);
      cand_bit = BIT_CANDIDATE_LEN(hdl);
  
      candidate_size = GET_BITFIELD_16(data, j, cand_bit);
      bit_all += cand_bit;
  
      if (APPEND_YOMI_FLG(hdl) && STEM_TERMINETER(stem_data)) {
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
          j = (NJ_UINT16)(bit_all & 0x0007);
          yomi_bit = BIT_YOMI_LEN(hdl);
  
          yomi_size = GET_BITFIELD_16(data, j, yomi_bit);
          bit_all += yomi_bit;
      } else {
          yomi_size = 0;
      }
  
      stem_size = GET_BIT_TO_BYTE(bit_all);
      stem_size += candidate_size;
      stem_size += yomi_size;
      return stem_size;
  }
  
  static void get_stem_word(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, STEM_DATA_SET *stem_set, NJ_UINT8 check)
  {
      NJ_UINT8 flg_bit;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all = 0;
      NJ_UINT16 bit;
      NJ_UINT16 dpos = 0;
      NJ_INT16 next;
      NJ_UINT8 b;
      NJ_UINT8 *wkc;
  
      flg_bit = BIT_MUHENKAN_LEN(hdl);
      if (NJ_GET_DIC_FMT(hdl) != NJ_DIC_FMT_KANAKAN) {
          flg_bit++;
      }
  
      if (BIT_HINDO_LEN(hdl)) {
          bit_all = (NJ_UINT16)(TERM_BIT + flg_bit);
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
          j = (NJ_UINT16)(bit_all & 0x0007);
          stem_set->hindo = GET_BITFIELD_16(data, j, BIT_HINDO_LEN(hdl));
      } else {
          stem_set->hindo = 0;
      }
  
      stem_set->hindo_jitu = (NJ_UINT16)(*(HINDO_NO_TOP_ADDR(hdl) + stem_set->hindo));
      if (BIT_FHINSI(hdl)) {
  
          bit_all = (NJ_UINT16)(TERM_BIT + flg_bit + BIT_HINDO_LEN(hdl));
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
          j = (NJ_UINT16)(bit_all & 0x0007);
          stem_set->fhinsi = GET_BITFIELD_16(data, j, BIT_FHINSI(hdl));
      } else {
          stem_set->fhinsi = 0;
      }
  
      b = HINSI_NO_BYTE(hdl);
      wkc = (NJ_UINT8*)(HINSI_NO_TOP_ADDR(hdl) + (b * (NJ_UINT16)(stem_set->fhinsi)));
  
      if (b == 2) {
          stem_set->fhinsi_jitu = (NJ_UINT16)(NJ_INT16_READ(wkc));
      } else {
          stem_set->fhinsi_jitu = (NJ_UINT16)*wkc;
      }
  
      if (BIT_BHINSI(hdl)) {
  
          bit_all = (NJ_UINT16)(TERM_BIT + flg_bit + BIT_HINDO_LEN(hdl) + BIT_FHINSI(hdl));
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
          j = (NJ_UINT16)(bit_all & 0x0007);
  
          stem_set->bhinsi = GET_BITFIELD_16(data, j, BIT_BHINSI(hdl));
      } else {
          stem_set->bhinsi = 0;
      }
  
      wkc = (NJ_UINT8*)(HINSI_NO_TOP_ADDR(hdl)
                        + (b * (FHINSI_NO_CNT(hdl) + (NJ_UINT16)(stem_set->bhinsi))));
      if (b == 2) {
          stem_set->bhinsi_jitu = (NJ_UINT16)(NJ_INT16_READ(wkc));
      } else {
          stem_set->bhinsi_jitu = (NJ_UINT16)*wkc;
      }
  
      if (check != 1) {
  
          bit_all = (NJ_UINT16)(TERM_BIT + flg_bit +
                                BIT_HINDO_LEN(hdl) +
                                BIT_FHINSI(hdl) +
                                BIT_BHINSI(hdl));
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
          j = (NJ_UINT16)(bit_all & 0x0007);
          bit = BIT_CANDIDATE_LEN(hdl);
  
          stem_set->candidate_size = GET_BITFIELD_16(data, j, bit);
          bit_all += bit;
      }
  
      if (check == 0) {
          stem_set->yomi_size = 0;
          if (APPEND_YOMI_FLG(hdl) && STEM_TERMINETER(stem_data)) {
              pos = (NJ_UINT16)(bit_all >> 3);
              data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
              j = (NJ_UINT16)(bit_all & 0x0007);
              bit = BIT_YOMI_LEN(hdl);
  
              stem_set->yomi_size = GET_BITFIELD_16(data, j, bit);
              bit_all += bit;
  
              dpos = GET_BIT_TO_BYTE(bit_all);
              dpos += stem_set->candidate_size;
  
          } else if (APPEND_YOMI_FLG(hdl)) {
              while (!(STEM_TERMINETER(stem_data))) {
                  next = get_stem_next(hdl, stem_data);
                  stem_data += next;
              }
              dpos = get_stem_yomi_data(hdl, stem_data, stem_set);
          }
  
          if (stem_set->yomi_size) {
              stem_set->yomi_size = get_stem_yomi_size(hdl, stem_data + dpos, stem_set->yomi_size);
          }
      }
  }
  
  static void get_stem_cand_data(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, STEM_DATA_SET *stem_set)
  {
      NJ_UINT8 flg_bit;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all;
      NJ_UINT16 cand_bit, yomi_bit;
  
      flg_bit = BIT_MUHENKAN_LEN(hdl);
      if (NJ_GET_DIC_FMT(hdl) != NJ_DIC_FMT_KANAKAN) {
          flg_bit++;
      }
  
      bit_all = (NJ_UINT16)(TERM_BIT + flg_bit +
                            BIT_HINDO_LEN(hdl) +
                            BIT_FHINSI(hdl) +
                            BIT_BHINSI(hdl));
      pos = (NJ_UINT16)(bit_all >> 3);
      data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
      cand_bit = BIT_CANDIDATE_LEN(hdl);
      j = (NJ_UINT16)(bit_all & 0x0007);
  
      stem_set->candidate_size = GET_BITFIELD_16(data, j, cand_bit);
      bit_all += cand_bit;
  
      if (APPEND_YOMI_FLG(hdl) && STEM_TERMINETER(stem_data)) {
          yomi_bit = BIT_YOMI_LEN(hdl);
          bit_all += yomi_bit;
      }
  
      stem_set->stem_size = GET_BIT_TO_BYTE(bit_all);
  }
  
  static NJ_UINT16 get_stem_yomi_data(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data,STEM_DATA_SET *stem_set)
  {
      NJ_UINT16 flg_bit;
      NJ_UINT16 data;
      NJ_UINT16 cand_bit, yomi_bit;
      NJ_UINT16 pos, j, bit_all;
      NJ_UINT16 yomi_pos;
      NJ_UINT16 candidate_size;
  
      flg_bit = BIT_MUHENKAN_LEN(hdl);
      if (NJ_GET_DIC_FMT(hdl) != NJ_DIC_FMT_KANAKAN) {
          flg_bit++;
      }
  
      bit_all = (NJ_UINT16)(TERM_BIT + flg_bit + BIT_HINDO_LEN(hdl) +
                            BIT_FHINSI(hdl) + BIT_BHINSI(hdl));
      pos = (NJ_UINT16)(bit_all >> 3);
      data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
      j = (NJ_UINT16)(bit_all & 0x0007);
  
      cand_bit = BIT_CANDIDATE_LEN(hdl);
      candidate_size = GET_BITFIELD_16(data, j, cand_bit);
  
      bit_all += cand_bit;
  
      if (APPEND_YOMI_FLG(hdl) && STEM_TERMINETER(stem_data)) {
          pos = (NJ_UINT16)(bit_all >> 3);
          data = (NJ_UINT16)(NJ_INT16_READ(stem_data + pos));
  
          j = (NJ_UINT16)(bit_all & 0x0007);
          yomi_bit = BIT_YOMI_LEN(hdl);
  
          stem_set->yomi_size = GET_BITFIELD_16(data, j, yomi_bit);
          bit_all += yomi_bit;
      } else {
          stem_set->yomi_size = 0;
      }
  
      yomi_pos = GET_BIT_TO_BYTE(bit_all);
      yomi_pos += candidate_size;
      return yomi_pos;
  }
  
  static NJ_UINT16 get_stem_yomi_size(NJ_DIC_HANDLE hdl, NJ_UINT8 *ydata, NJ_UINT16 yomi_size)
  {
      NJ_INT16 ytbl_cnt;
      NJ_INT8 ysize;
      NJ_UINT8 *ytbl_top;
      NJ_UINT8 *ytbl;
      NJ_UINT8 yidx;
      NJ_UINT16 i;
      NJ_UINT16 len;
  
      ytbl_cnt = YOMI_INDX_CNT(hdl);
  
      if (ytbl_cnt) {
          ysize = YOMI_INDX_SIZE(hdl);
          ytbl_top = YOMI_INDX_TOP_ADDR(hdl);
          len = 0;
          for (i = 0; i < yomi_size; i++) {
              if (ysize == 2) {
                  yidx = *(ydata+i);
                  ytbl = ytbl_top + ((yidx-1) * ysize);
                  len += UTL_CHAR(ytbl);
              } else {
                  len++;
              }
          }
          return len * sizeof(NJ_CHAR);
      } else {
          return yomi_size;
      }
  }
  
  static NJ_UINT16 get_stem_yomi_string(NJ_DIC_HANDLE hdl, NJ_UINT8 *stem_data, NJ_CHAR *yomi, NJ_UINT16 yomi_pos, NJ_UINT16 yomi_size, NJ_UINT16 size)
  {
      NJ_INT16 ytbl_cnt;
      NJ_INT8 ysize;
      NJ_UINT8 *ytbl_top, *ytbl;
      NJ_UINT8 *ydata;
      NJ_UINT8 yidx;
      NJ_UINT16 i;
      NJ_UINT16 copy_len;
      NJ_UINT16 char_len;
  
      ytbl_cnt = YOMI_INDX_CNT(hdl);
      ysize    = YOMI_INDX_SIZE(hdl);
      ytbl_top = YOMI_INDX_TOP_ADDR(hdl);
  
      ydata = stem_data + yomi_pos;
  
      if (ytbl_cnt) {
          copy_len = 0;
          for (i = 0; i < yomi_size; i++) {
              yidx = *(ydata + i);
              ytbl = ytbl_top + ((yidx - 1) * ysize);
              if (ysize == 2) {
                  char_len = UTL_CHAR(ytbl);
                  if (((copy_len + char_len + NJ_TERM_LEN) * sizeof(NJ_CHAR)) > size) {
                      return size;
                  }
                  while (char_len > 0) {
                      NJ_CHAR_COPY(yomi + copy_len, ytbl);
                      copy_len++;
                      char_len--;
                      ytbl += sizeof(NJ_CHAR);
                  }
              } else {
                  if (((copy_len + 1 + NJ_TERM_LEN) * sizeof(NJ_CHAR)) > size) {
                      return size;
                  }
                  *(yomi + copy_len) = (NJ_CHAR)(*ytbl);
                  copy_len++;
              }
          }
      } else {
          if ((yomi_size + (NJ_TERM_LEN * sizeof(NJ_CHAR))) > size) {
              return size;
          }
          nj_memcpy((NJ_UINT8*)yomi, ydata, yomi_size);
          copy_len = yomi_size / sizeof(NJ_CHAR);
      }
      *(yomi + copy_len) = NJ_CHAR_NUL;
      return copy_len;
  }
  
  static NJ_INT16 search_node(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset)
  {
      NJ_UINT8 *root, *now, *node, *node_mid;
      NJ_UINT8 index;
      NJ_UINT8 *byomi;
      NJ_UINT8 *wkc;
      NJ_UINT8 idx_no;
      NJ_INT16 idx;
      NJ_INT16 char_size;
      NJ_INT16 left, right, mid;
      NJ_INT16 ytbl_cnt;
      NJ_UINT16 c, d;
      NJ_UINT8  c1 = 0, c2 = 0;
      NJ_UINT16 y;
      NJ_UINT16 ysize = (condition->ylen * sizeof(NJ_CHAR));
      NJ_UINT8 *ytbl_top;
      NJ_UINT16 idx_cnt;
      NJ_UINT16 nd_index;
      NJ_UINT16 bit_left, bit_data;
      NJ_UINT32 data_offset;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all, bit_tmp, bit_idx;
      NJ_UINT32 data_l;
      NJ_UINT8 restart_flg = 0;
      NJ_UINT8 bottom_flg = 0;
      NJ_UINT8 *data_top, *stem_data;
      NJ_UINT16 hindo, hindo_max;
      NJ_UINT32 current,hindo_max_data, bottom, next;
  
      node = NULL;
      byomi = (NJ_UINT8*)(condition->yomi);
      root = NODE_AREA_TOP_ADDR(loctset->loct.handle);
  
      node_mid = root + NODE_AREA_MID_ADDR(loctset->loct.handle);
      now = node_mid;
  
      idx_no = 0;
      idx_cnt = 1;
  
      bit_left = BIT_NODE_AREA_LEFT_LEN(loctset->loct.handle);
      bit_data = BIT_NODE_AREA_DATA_LEN(loctset->loct.handle);
  
      ytbl_cnt = YOMI_INDX_CNT(loctset->loct.handle);
      y = YOMI_INDX_SIZE(loctset->loct.handle);
      ytbl_top = YOMI_INDX_TOP_ADDR(loctset->loct.handle);
  
      data_top = STEM_AREA_TOP_ADDR(loctset->loct.handle);
  
      if ((condition->operation == NJ_CUR_OP_FORE) &&
          NJ_CHAR_STRLEN_IS_0(condition->yomi)) {
          ysize = 0;
          node = root;
      }
  
      while (ysize > 0) {
          if (ytbl_cnt != 0) {
              char_size = UTL_CHAR(byomi) * sizeof(NJ_CHAR);
              if (char_size > 2) {
                  loctset->loct.status = NJ_ST_SEARCH_END_EXT;
                  return 0;
              }
  
              if (char_size == 2) {
                  if (y == 1) {
                      return 0;
                  }
                  c1 = *byomi;
                  c2 = *(byomi + 1);
                  c = (NJ_UINT16)((c1 << 8) | c2);
              } else {
  
                  c1 = *byomi;
                  c2 = 0x00;
                  c = (NJ_UINT16)(*byomi);
              }
  
              idx = -1;
              left = 0;
              right = ytbl_cnt;
  
              if (y == 2) {
                  while (left <= right) {
                      mid = (left + right) >> 1;
                      wkc = ytbl_top + (mid << 1);
  
                      if (c1 == *wkc) {
                          if (c2 == *(wkc + 1)) {
                              idx = (NJ_UINT16)(mid + 1);
                              break;
                          }
                          if (c2 < *(wkc + 1)) {
                              right = mid - 1;
                          } else {
                              left = mid + 1;
                          }
                      } else if (c1 < *wkc) {
                          right = mid - 1;
                      } else {
                          left = mid + 1;
                      }
                  }
              } else {
                  while (left <= right) {
                      mid = (left + right) >> 1;
                      wkc = ytbl_top + (mid * y);
                      d = (NJ_UINT16)(*wkc);
                      if (c == d) {
                          idx = (NJ_UINT16)(mid + 1);
                          break;
                      }
                      if (c < d) {
                          right = mid - 1;
                      } else {
                          left = mid + 1;
                      }
                  }
              }
  
              if (idx < 0) {
                  loctset->loct.status = NJ_ST_SEARCH_END_EXT;
                  return 0;
              }
              index = (NJ_UINT8)idx;
          } else {
              index = *byomi;
              char_size = 1;
          }
  
          byomi += char_size;
          ysize -= char_size;
  
          while (now < data_top) {
              if (NODE_IDX_EXIST(now)) {
                  bit_idx = 8;
                  idx_cnt = NODE_IDX_CNT(now);
              } else {
                  bit_idx = 4;
                  idx_cnt = 1;
              }
              bit_all = bit_idx;
  
              if (NODE_LEFT_EXIST(now)) {
                  bit_all += bit_left;
              }
  
              if (NODE_DATA_EXIST(now)) {
                  bit_all += bit_data;
              }
  
              bit_tmp = bit_all;
  
              bit_all += (NJ_UINT16)(idx_no << 3);
  
              pos = (NJ_UINT16)(bit_all >> 3);
  
              data = (NJ_UINT16)(NJ_INT16_READ(now + pos));
  
              j = (NJ_UINT16)(bit_all & 0x0007);
  
              nd_index = GET_BITFIELD_16(data, j, INDEX_BIT);
              if (index == (NJ_UINT8)nd_index) {
                  break;
              } else {
                  if ((!NODE_TERM(now)) && (index > (NJ_UINT8)nd_index) && (idx_no == 0)) {
                      now += GET_BIT_TO_BYTE(bit_tmp + (idx_cnt * 8));
                      if (now == node_mid) {
                          loctset->loct.status = NJ_ST_SEARCH_END_EXT;
                          return 0;
                      }
                      continue;
                  } else {
                      if ((now == node_mid) && (restart_flg == 0) &&
                          (index < (NJ_UINT8)nd_index) && (idx_no == 0) &&
                          (root != node_mid)) {
                          now = root;
                          idx_no = 0;
                          restart_flg = 1;
                          continue;
                      }
                      loctset->loct.status = NJ_ST_SEARCH_END_EXT;
                      return 0;
                  }
              }
          }
  
          if ( (idx_cnt > (NJ_UINT16)(idx_no + 1))) {
              if (ysize == 0) {
                  if (condition->operation == NJ_CUR_OP_FORE) {
                      node = now;
                      break;
                  }
                  loctset->loct.status = NJ_ST_SEARCH_END;
                  return 0;
              }
              idx_no++;
              continue;
          }
          node = now;
          idx_no = 0;
  
          if (ysize == 0) {
              break;
          } else {
              if (!(NODE_LEFT_EXIST(now))) {
                  loctset->loct.status = NJ_ST_SEARCH_END_EXT;
                  return 0;
              }
          }
  
          if (NODE_IDX_EXIST(now)) {
              bit_idx = 8;
          } else {
              bit_idx = 4;
          }
          pos = (NJ_UINT16)(bit_idx >> 3);
          data_l = (NJ_UINT32)(NJ_INT32_READ(now + pos));
          j = (NJ_UINT16)(bit_idx & 0x0007);
          now += GET_BITFIELD_32(data_l, j, bit_left);
      }
      now = node;
  
      if ((node == NULL) || !(NODE_DATA_EXIST(node))) {
          if ((condition->operation == NJ_CUR_OP_FORE) &&
              (node != NULL)) {
              while (!NODE_DATA_EXIST(node)) {
                  if (!(NODE_LEFT_EXIST(node))) {
                      loctset->loct.status = NJ_ST_SEARCH_END;
                      return 0;
                  }
                  if (NODE_IDX_EXIST(node)) {
                      bit_idx = 8;
                  } else {
                      bit_idx = 4;
                  }
                  pos = (NJ_UINT16)(bit_idx >> 3);
                  data_l = (NJ_UINT32)(NJ_INT32_READ(node + pos));
                  j = (NJ_UINT16)(bit_idx & 0x0007);
                  node += GET_BITFIELD_32(data_l, j, bit_left);
              }
          } else {
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
      }
  
      if (NODE_IDX_EXIST(node)) {
          bit_idx = 8;
      } else {
          bit_idx = 4;
      }
  
      if (NODE_LEFT_EXIST(node)) {
          bit_all = bit_idx + bit_left;
      } else {
          bit_all = bit_idx;
      }
  
      pos = (NJ_UINT16)(bit_all >> 3);
      data_l = (NJ_UINT32)(NJ_INT32_READ(node + pos));
  
      j = (NJ_UINT16)(bit_all & 0x0007);
      data_offset = GET_BITFIELD_32(data_l, j, bit_data);
  
      loctset->loct.top = data_offset;
      loctset->loct.current = 0;
  
      if (condition->operation == NJ_CUR_OP_FORE) {
          bottom = loctset->loct.top;
          if (NJ_CHAR_STRLEN_IS_0(condition->yomi)) {
              node = node_mid;
          } else {
              node = now;
              if (NODE_LEFT_EXIST(node)) {
                  if (NODE_IDX_EXIST(node)) {
                      bit_all = 8;
                  } else {
                      bit_all = 4;
                  }
                  pos = (NJ_UINT16)(bit_all >> 3);
                  data_l = (NJ_UINT32)(NJ_INT32_READ(node + pos));
  
                  j = (NJ_UINT16)(bit_all & 0x0007);
                  node += GET_BITFIELD_32(data_l, j, bit_left);
              } else {
                  bottom_flg = 1;
              }
          }
  
          if (!bottom_flg) {
              while (node < data_top) {
                  if (!NODE_TERM(node)) {
                      if (NODE_IDX_EXIST(node)) {
                          bit_all = 8;
                          idx_cnt = NODE_IDX_CNT(node);
                      } else {
                          bit_all = 4;
                          idx_cnt = 1;
                      }
                      if (NODE_LEFT_EXIST(node)) {
                          bit_all += bit_left;
                      }
                      if (NODE_DATA_EXIST(node)) {
                          bit_all += bit_data;
                      }
                      node += GET_BIT_TO_BYTE(bit_all + (idx_cnt * 8));
                  } else {
                      if (!NODE_LEFT_EXIST(node)) {
                          if (NODE_DATA_EXIST(node)) {
                              if (NODE_IDX_EXIST(node)) {
                                  bit_all = 8;
                              } else {
                                  bit_all = 4;
                              }
                              pos = (NJ_UINT16)(bit_all >> 3);
                              data_l = (NJ_UINT32)(NJ_INT32_READ(node + pos));
  
                              j = (NJ_UINT16)(bit_all & 0x0007);
                              data_offset = GET_BITFIELD_32(data_l, j, bit_data);
  
                              bottom = data_offset;
                              break;
                          } else {
                              return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_DIC_BROKEN);
                          }
                      } else {
                          if (NODE_IDX_EXIST(node)) {
                              bit_all = 8;
                          } else {
                              bit_all = 4;
                          }
                          pos = (NJ_UINT16)(bit_all >> 3);
                          data_l = (NJ_UINT32)(NJ_INT32_READ(node + pos));
                          j = (NJ_UINT16)(bit_all & 0x0007);
                          node += GET_BITFIELD_32(data_l, j, bit_left);
                      }
                  }
              }
          }
  
          stem_data = data_top + bottom;
  
          while (!(STEM_TERMINETER(stem_data))) {
              next = get_stem_next(loctset->loct.handle, stem_data);
              stem_data += next;
          }
          loctset->loct.bottom = (NJ_UINT32)(stem_data - data_top);
  
          stem_data = data_top + loctset->loct.top;
          hindo = (NJ_UINT16) *((NJ_UINT8*)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                            + get_stem_hindo(loctset->loct.handle, stem_data)));
          hindo_max = hindo;
          hindo_max_data = 0;
  
          if (condition->mode == NJ_CUR_MODE_FREQ) {
              j = get_stem_next(loctset->loct.handle, stem_data);
              current = j;
              stem_data += j;
              while (stem_data <= (data_top + loctset->loct.bottom)) {
                  hindo = (NJ_UINT16) *((NJ_UINT8*)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                                    + get_stem_hindo(loctset->loct.handle, stem_data)));
                  if (hindo > hindo_max) {
                      hindo_max = hindo;
                      hindo_max_data = current;
                  }
                  j = get_stem_next(loctset->loct.handle, stem_data);
                  current += j;
                  stem_data += j;
              }
          }
          loctset->cache_freq = CALCULATE_HINDO(hindo_max, loctset->dic_freq.base,
                                                loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
          loctset->loct.current = hindo_max_data;
  
      }
  
      return 1;
  }
  
  static NJ_INT16 bdic_search_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset)
  {
      NJ_UINT8 *data, *data_end;
      NJ_INT16 i, current = 0;
      NJ_UINT16 hindo;
  
  
      data = STEM_AREA_TOP_ADDR(loctset->loct.handle);
      data += loctset->loct.top + loctset->loct.current;
  
      if (GET_LOCATION_STATUS(loctset->loct.status) != NJ_ST_SEARCH_NO_INIT) {
  
          if (STEM_TERMINETER(data)) {
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
  
          i = get_stem_next(loctset->loct.handle, data);
  
          data += i;
          current += i;
      }
  
      if (NJ_GET_DIC_FMT(loctset->loct.handle) == NJ_DIC_FMT_KANAKAN) {
          data_end = loctset->loct.handle
              + NJ_DIC_COMMON_HEADER_SIZE
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_DATA_SIZE)
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_EXT_SIZE)
              - NJ_DIC_ID_LEN;
      } else {
          data_end = CAND_IDX_AREA_TOP_ADDR(loctset->loct.handle);
      }
  
      if (data < data_end) {
  
          loctset->loct.status = NJ_ST_SEARCH_READY;
          loctset->loct.current += current;
          hindo = (NJ_UINT16) *((NJ_UINT8*)(HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                            get_stem_hindo(loctset->loct.handle, data)));
          loctset->cache_freq = CALCULATE_HINDO(hindo, loctset->dic_freq.base,
                                                loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
          return 1;
      }
  
      loctset->loct.status = NJ_ST_SEARCH_END;
      return 0;
  }
  
  static NJ_INT16 bdic_search_fore_data(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset)
  {
      NJ_UINT8 *data, *data_top, *bottom, *data_end;
      NJ_INT16 i = 0;
      NJ_INT16 hindo = 0;
      NJ_INT16 hindo_max = -1;
      NJ_UINT8 no_hit = 0;
      NJ_UINT32 current = loctset->loct.current;
      NJ_UINT8 *current_org;
      NJ_UINT32 hindo_data = 0;
  
      if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_NO_INIT) {
          loctset->loct.status = NJ_ST_SEARCH_READY;
          loctset->loct.current_info = CURRENT_INFO_SET;
          return 1;
      }
  
      data_top = STEM_AREA_TOP_ADDR(loctset->loct.handle);
  
      data = data_top + loctset->loct.top + loctset->loct.current;
  
      current_org = data;
  
      bottom = data_top + loctset->loct.bottom;
  
      if (NJ_GET_DIC_FMT(loctset->loct.handle) == NJ_DIC_FMT_KANAKAN) {
          data_end = loctset->loct.handle
              + NJ_DIC_COMMON_HEADER_SIZE
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_DATA_SIZE)
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_EXT_SIZE)
              - NJ_DIC_ID_LEN;
      } else {
          data_end = CAND_IDX_AREA_TOP_ADDR(loctset->loct.handle);
      }
  
      if (condition->mode == NJ_CUR_MODE_FREQ) {
  
          while (data < data_end) {
              i = get_stem_next(loctset->loct.handle, data);
              data += i;
              current += i;
  
              if (data > bottom) {
                  if (loctset->cache_freq == 0) {
                      loctset->loct.status = NJ_ST_SEARCH_END;
                      return 0;
                  } else if (no_hit == 1) {
                      loctset->loct.status = NJ_ST_SEARCH_END;
                      return 0;
                  }
  
                  loctset->cache_freq -= 1;
  
                  data = data_top + loctset->loct.top;
                  current = 0;
  
                  no_hit = 1;
              }
  
  
              if ((hindo_max != -1) && (data == current_org)) {
                  loctset->loct.status = NJ_ST_SEARCH_READY;
                  loctset->loct.current_info = CURRENT_INFO_SET;
                  loctset->loct.current = hindo_data;
                  loctset->cache_freq = hindo_max;
                  return 1;
              }
  
  
              hindo = (NJ_INT16) *((NJ_UINT8*)(HINDO_NO_TOP_ADDR(loctset->loct.handle) + get_stem_hindo(loctset->loct.handle, data)));
              hindo = CALCULATE_HINDO(hindo, loctset->dic_freq.base,
                                      loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
  
              if (hindo == loctset->cache_freq) {
                  loctset->loct.status = NJ_ST_SEARCH_READY;
                  loctset->loct.current_info = CURRENT_INFO_SET;
                  loctset->loct.current = current;
                  return 1;
              }
  
              if (hindo < loctset->cache_freq) {
                  if (((hindo == hindo_max) && (current < hindo_data)) ||
                      (hindo > hindo_max)) {
                      hindo_max = hindo;
                      hindo_data = current;
                  }
              }
          }
      } else {
          i = get_stem_next(loctset->loct.handle, data);
          data += i;
          current += i;
  
          if (data > bottom) {
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
  
          hindo = (NJ_INT16) *((NJ_UINT8*)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                           + get_stem_hindo(loctset->loct.handle, data)));
          loctset->cache_freq = CALCULATE_HINDO(hindo, loctset->dic_freq.base,
                                                loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
          loctset->loct.status = NJ_ST_SEARCH_READY;
          loctset->loct.current_info = CURRENT_INFO_SET;
          loctset->loct.current = current;
          return 1;
      }
  
      loctset->loct.status = NJ_ST_SEARCH_END;
      return 0;
  }
  
  NJ_INT16 njd_b_search_word(NJ_SEARCH_CONDITION *con, NJ_SEARCH_LOCATION_SET *loctset)
  {
      NJ_INT16 ret;
      NJ_DIC_INFO *pdicinfo;
      NJ_UINT16 hIdx;
  
      switch (con->operation) {
      case NJ_CUR_OP_COMP:
          if (con->mode != NJ_CUR_MODE_FREQ) {
              loctset->loct.status = NJ_ST_SEARCH_END_EXT;
              return 0;
          }
          break;
      case NJ_CUR_OP_FORE:
          if (APPEND_YOMI_FLG(loctset->loct.handle) == 0) {
              loctset->loct.status = NJ_ST_SEARCH_END_EXT;
              return 0;
          }
          if ((NJ_GET_DIC_TYPE_EX(loctset->loct.type, loctset->loct.handle) != NJ_DIC_TYPE_CUSTOM_COMPRESS)
              && NJ_CHAR_STRLEN_IS_0(con->yomi)) {
              loctset->loct.status = NJ_ST_SEARCH_END_EXT;
              return 0;
          }
          break;
      default:
          loctset->loct.status = NJ_ST_SEARCH_END_EXT;
          return 0;
      }
  
      if (con->ylen > NJ_GET_MAX_YLEN(loctset->loct.handle)) {
          loctset->loct.status = NJ_ST_SEARCH_END_EXT;
          return 0;
      }
  
      if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_NO_INIT) {
          switch (con->operation) {
          case NJ_CUR_OP_COMP:
              ret = search_node(con, loctset);
              if (ret < 1) {
                  return ret;
              }
              ret = bdic_search_data(con, loctset);
              if (ret < 1) {
  
                  loctset->loct.status = NJ_ST_SEARCH_END;
              }
              break;
          case NJ_CUR_OP_FORE:
              pdicinfo = con->ds->dic;
              for (hIdx = 0; (hIdx < NJ_MAX_DIC) && (pdicinfo->handle != loctset->loct.handle); hIdx++) {
                  pdicinfo++;
              }
  
              if (hIdx == NJ_MAX_DIC) {
  
                  loctset->loct.status = NJ_ST_SEARCH_END;
                  return 0;
              }
  
              if ((con->ds->dic[hIdx].srhCache == NULL) || (con->ylen == 0) ||
                  !(con->ds->mode & 0x0001)) {
                  ret = search_node(con, loctset);
                  if (ret < 1) {
                      return ret;
                  }
                  ret = bdic_search_fore_data(con, loctset);
              } else {
                  ret = search_node2(con, loctset, hIdx);
                  if (ret == NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_NOT_ENOUGH)) {
  
                      NJ_SET_CACHEOVER_TO_SCACHE(con->ds->dic[hIdx].srhCache);
                      ret = search_node2(con, loctset, hIdx);
                  }
                  if (ret < 1) {
                      return ret;
                  }
                  ret = bdic_search_fore_data2(con, loctset, hIdx);
              }
              if (ret < 1) {
  
                  loctset->loct.status = NJ_ST_SEARCH_END;
              }
              break;
          default:
              loctset->loct.status = NJ_ST_SEARCH_END_EXT;
              return 0;
          }
      } else if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_READY) {
          switch (con->operation) {
          case NJ_CUR_OP_COMP:
              ret = bdic_search_data(con, loctset);
              if (ret < 1) {
  
                  loctset->loct.status = NJ_ST_SEARCH_END;
              }
              break;
          case NJ_CUR_OP_FORE:
              pdicinfo = con->ds->dic;
              for (hIdx = 0; (hIdx < NJ_MAX_DIC) && (pdicinfo->handle != loctset->loct.handle); hIdx++) {
                  pdicinfo++;
              }
  
              if (hIdx == NJ_MAX_DIC) {
                  loctset->loct.status = NJ_ST_SEARCH_END;
                  return 0;
              }
  
              if ((con->ds->dic[hIdx].srhCache == NULL) || (con->ylen == 0) ||
                  !(con->ds->mode & 0x0001)) {
                  ret = bdic_search_fore_data(con, loctset);
              } else {
                  ret = bdic_search_fore_data2(con, loctset, hIdx);
              }
              if (ret < 1) {
                  loctset->loct.status = NJ_ST_SEARCH_END;
              }
              break;
          default:
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
      } else {
          loctset->loct.status = NJ_ST_SEARCH_END;
          return 0;
      }
      return ret;
  }
  
  NJ_INT16 njd_b_get_word(NJ_SEARCH_LOCATION_SET *loctset, NJ_WORD *word)
  {
      NJ_UINT8 *data;
      STEM_DATA_SET stem_set;
      NJ_UINT8 check;
  
      if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_END) {
          return 0;
      }
  
      if (GET_LOCATION_OPERATION(loctset->loct.status) == NJ_CUR_OP_FORE) {
          data = STEM_AREA_TOP_ADDR(loctset->loct.handle);
          data += loctset->loct.top + loctset->loct.current;
          check = 0;
      } else {
          data = STEM_AREA_TOP_ADDR(loctset->loct.handle);
          data += loctset->loct.top + loctset->loct.current;
          check = 2;
      }
  
      get_stem_word(loctset->loct.handle, data, &stem_set, check);
  
      if (GET_LOCATION_OPERATION(loctset->loct.status) == NJ_CUR_OP_FORE) {
          word->stem.info1 = (NJ_UINT16)(stem_set.yomi_size / sizeof(NJ_CHAR));
      }
      word->stem.info1 = WORD_LEN(word->stem.info1);
      word->stem.info1 |= (NJ_UINT16)(stem_set.fhinsi_jitu << 7);
  
      if (check != 1) {
          if (stem_set.candidate_size == 0) {
              if (GET_LOCATION_OPERATION(loctset->loct.status) == NJ_CUR_OP_FORE) {
                  word->stem.info2 = (NJ_UINT16)(stem_set.yomi_size / sizeof(NJ_CHAR));
              } else {
                  word->stem.info2 = (NJ_UINT16)NJ_GET_YLEN_FROM_STEM(word);
              }
          } else {
              word->stem.info2 = (NJ_UINT16)(stem_set.candidate_size / sizeof(NJ_CHAR));
          }
      } else {
          word->stem.info2 = (NJ_UINT16)NJ_GET_YLEN_FROM_STEM(word);
      }
  
      word->stem.info2 = WORD_LEN(word->stem.info2);
      word->stem.info2 |= (NJ_UINT16)(stem_set.bhinsi_jitu << 7);
      word->stem.hindo = CALCULATE_HINDO(stem_set.hindo_jitu, loctset->dic_freq.base,
                                         loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
      word->stem.loc = loctset->loct;
  
      return 1;
  }
  
  NJ_INT16 njd_b_get_candidate(NJ_WORD *word, NJ_CHAR *candidate, NJ_UINT16 size)
  {
      NJ_SEARCH_LOCATION *loc;
      NJ_CHAR  *wkc, *cand;
      NJ_UINT8  *wkd;
      NJ_UINT8 *data;
      NJ_UINT8 *data_org;
      NJ_UINT16 len, j;
      STEM_DATA_SET stem_set;
      NJ_INT16  next;
      NJ_UINT16 yomi_pos;
      NJ_CHAR   ybuf[NJ_MAX_LEN + NJ_TERM_LEN];
  
      if ((GET_LOCATION_OPERATION(word->stem.loc.status) == NJ_CUR_OP_COMP) ||
          (GET_LOCATION_OPERATION(word->stem.loc.status) == NJ_CUR_OP_FORE)) {
  
          loc = &word->stem.loc;
          data = STEM_AREA_TOP_ADDR(loc->handle);
          data += loc->top + loc->current;
  
          get_stem_cand_data(loc->handle, data, &stem_set);
          len = stem_set.candidate_size / sizeof(NJ_CHAR);
  
      } else {
          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_CANDIDATE, NJ_ERR_INVALID_RESULT);
      }
  
      if (len == 0) {
          data_org = data;
  
          if (GET_LOCATION_OPERATION(word->stem.loc.status) == NJ_CUR_OP_COMP) {
              len = WORD_LEN(word->stem.info1);
              if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
                  return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_CANDIDATE, NJ_ERR_BUFFER_NOT_ENOUGH);
              }
              wkc = word->yomi;
          } else {
              while (!(STEM_TERMINETER(data))) {
                  next = get_stem_next(loc->handle, data);
                  data += next;
              }
  
              yomi_pos = get_stem_yomi_data(loc->handle, data, &stem_set);
  
              wkc = ybuf;
              len = get_stem_yomi_string(loc->handle, data, wkc,
                                         yomi_pos, stem_set.yomi_size,
                                         size);
  
              if (size < ((len + NJ_TERM_LEN) * sizeof(NJ_CHAR))) {
                  return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_CANDIDATE, NJ_ERR_BUFFER_NOT_ENOUGH);
              }
          }
  
          if (STEM_NO_CONV_FLG(data_org) == 0) {
              cand = candidate;
              for (j = 0; j < len; j++) {
                  *cand++ = *wkc++;
              }
              *cand = NJ_CHAR_NUL;
          } else {
              nje_convert_hira_to_kata(wkc, candidate, len);
          }
      } else {
          if (size < (stem_set.candidate_size + (NJ_TERM_LEN*sizeof(NJ_CHAR)))) {
              return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_CANDIDATE, NJ_ERR_BUFFER_NOT_ENOUGH);
          }
          wkc = candidate;
          wkd = data + stem_set.stem_size;
          for (j = 0; j < len; j++) {
              NJ_CHAR_COPY(wkc, wkd);
              wkd += sizeof(NJ_CHAR);
              wkc++;
          }
          *wkc = NJ_CHAR_NUL;
      }
  
      return len;
  }
  
  NJ_INT16 njd_b_get_stroke(NJ_WORD *word, NJ_CHAR *stroke, NJ_UINT16 size)
  {
      NJ_SEARCH_LOCATION *loc;
      NJ_UINT8 *data;
      NJ_INT16 len;
      NJ_INT16 next;
      NJ_UINT16 yomi_pos;
      STEM_DATA_SET stem_set;
  
      if (GET_LOCATION_OPERATION(word->stem.loc.status) == NJ_CUR_OP_FORE) {
          if (NJ_GET_YLEN_FROM_STEM(word) == 0) {
              return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_STROKE, NJ_ERR_INVALID_RESULT);
          }
          loc = &word->stem.loc;
  
          data = STEM_AREA_TOP_ADDR(loc->handle);
          data += loc->top + loc->current;
      } else {
          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_STROKE, NJ_ERR_INVALID_RESULT);
      }
  
      while (!(STEM_TERMINETER(data))) {
          next = get_stem_next(loc->handle, data);
          data += next;
      }
  
      yomi_pos = get_stem_yomi_data(loc->handle, data, &stem_set);
      if (stem_set.yomi_size == 0) {
  
          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_STROKE, NJ_ERR_INVALID_RESULT);
      }
  
      len = get_stem_yomi_string(loc->handle, data, stroke,
                                 yomi_pos, stem_set.yomi_size,
                                 size);
  
      if (size < (NJ_UINT16)((len+NJ_TERM_LEN)*sizeof(NJ_CHAR))) {
          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_GET_STROKE, NJ_ERR_BUFFER_NOT_ENOUGH);
      }
  
      *(stroke + len) = NJ_CHAR_NUL;
      return len;
  }
  
  static NJ_INT16 search_node2(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset, NJ_UINT16 hidx)
  {
      NJ_UINT8 *root, *now, *node, *node_mid;
      NJ_CHAR  *yomi;
  
      NJ_INT16 ytbl_cnt;
      NJ_UINT16 y;
      NJ_UINT8 *ytbl_top;
  
      NJ_UINT16 bit_left, bit_data;
      NJ_UINT32 data_offset;
      NJ_UINT16 j;
      NJ_UINT8 *data_top, *stem_data;
      NJ_UINT16 hindo, hindo_max, hindo_tmp;
      NJ_UINT32 current, hindo_max_data, hindo_tmp_data;
  
      NJ_SEARCH_CACHE *psrhCache = condition->ds->dic[hidx].srhCache;
      NJ_CHAR  *key;
      NJ_UINT8 cmpflg;
      NJ_UINT8 endflg;
      NJ_UINT16 abPtrIdx;
      NJ_UINT16 key_len;
      NJ_UINT16 i, l, m;
      NJ_UINT16 abIdx;
      NJ_UINT16 abIdx_current;
      NJ_UINT16 abIdx_old;
      NJ_UINT16 addcnt = 0;
      NJ_CHAR   char_tmp[NJ_MAX_LEN + NJ_TERM_LEN];
      NJ_UINT16 tmp_len;
      NJ_UINT16 endIdx;
      NJ_INT16 ret;
      NJ_UINT8 *con_node;
      NJ_UINT16 yomi_clen;
      NJ_UINT8 aimai_flg = 0x01;
      NJ_CHAR  key_tmp[NJ_MAX_CHAR_LEN + NJ_TERM_LEN];
      NJ_CACHE_INFO tmpbuff;
  
      if (NJ_GET_CACHEOVER_FROM_SCACHE(psrhCache)) {
          aimai_flg = 0x00;
      }
  
      node = NULL;
  
      yomi = condition->yomi;
  
      root = NODE_AREA_TOP_ADDR(loctset->loct.handle);
  
      node_mid = root + NODE_AREA_MID_ADDR(loctset->loct.handle);
      now = node_mid;
  
      bit_left = BIT_NODE_AREA_LEFT_LEN(loctset->loct.handle);
      bit_data = BIT_NODE_AREA_DATA_LEN(loctset->loct.handle);
  
      ytbl_cnt = YOMI_INDX_CNT(loctset->loct.handle);
      y = YOMI_INDX_SIZE(loctset->loct.handle);
      ytbl_top = YOMI_INDX_TOP_ADDR(loctset->loct.handle);
  
      data_top = STEM_AREA_TOP_ADDR(loctset->loct.handle);
  
      endflg = 0x00;
      cmpflg = 0x00;
      abPtrIdx = 0;
      key = condition->ds->keyword;
  
      yomi_clen = condition->yclen;
      for (i = 0; i < yomi_clen; i++) {
          abPtrIdx = i;
  
          if (!cmpflg) {
              if (((abPtrIdx != 0) && (psrhCache->keyPtr[abPtrIdx] == 0))
                  || (psrhCache->keyPtr[abPtrIdx + 1] == 0)) {
  
                  cmpflg = 0x01;
              } else {
              }
          }
  
          addcnt = 0;
          if (cmpflg) {
              if (abPtrIdx == 0) {
                  abIdx = 0;
  
                  nj_charncpy(key_tmp, yomi, 1);
                  key_len = nj_strlen(key_tmp);
  
                  node = NULL;
                  now = node_mid;
                  psrhCache->keyPtr[0] = 0;
  
                  ret = search_yomi_node(condition->operation,
                                         node, now, 0, key_tmp, key_len,
                                         root, node_mid, bit_left, bit_data,
                                         data_top, ytbl_cnt, y, ytbl_top,
                                         &tmpbuff,
                                         &con_node, &data_offset);
                  if (ret < 0) {
  
                  } else {
                      psrhCache->storebuff[abIdx] = tmpbuff;
                      now = con_node;
                      psrhCache->storebuff[abIdx].top = data_offset;
  
                      if (condition->operation == NJ_CUR_OP_FORE) {
                          ret = get_node_bottom(key_tmp, now, node_mid, data_top,
                                                bit_left, bit_data,
                                                psrhCache->storebuff[abIdx].top,
                                                loctset->loct.handle,
                                                &(psrhCache->storebuff[abIdx].bottom));
                          if (ret < 0) {
                              return ret;
                          }
                      }
                      addcnt++;
                      abIdx++;
                  }
  
                  if ((condition->charset != NULL) && aimai_flg) {
  
                      for (l = 0; l < condition->charset->charset_count; l++) {
  
                          if (nj_charncmp(key, condition->charset->from[l], 1) == 0) {
                              nj_strcpy(char_tmp, condition->charset->to[l]);
                              tmp_len = nj_strlen(char_tmp);
  
                              node = NULL;
                              now = node_mid;
  
                              ret = search_yomi_node(condition->operation,
                                                     node, now, 0, char_tmp, tmp_len,
                                                     root, node_mid, bit_left, bit_data,
                                                     data_top, ytbl_cnt, y, ytbl_top,
                                                     &tmpbuff,
                                                     &con_node, &data_offset);
  
                              if (ret < 0) {
  
                              } else {
  
                                  if (abIdx >= NJ_SEARCH_CACHE_SIZE) {
                                      psrhCache->keyPtr[abPtrIdx+1] = 0;
                                      return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_NOT_ENOUGH);
                                  }
  
                                  psrhCache->storebuff[abIdx] = tmpbuff;
  
                                  now = con_node;
  
                                  psrhCache->storebuff[abIdx].top = data_offset;
  
                                  if (condition->operation == NJ_CUR_OP_FORE) {
                                      ret = get_node_bottom(key_tmp, now,
                                                            node_mid, data_top,
                                                            bit_left, bit_data,
                                                            psrhCache->storebuff[abIdx].top,
                                                            loctset->loct.handle,
                                                            &(psrhCache->storebuff[abIdx].bottom));
                                      if (ret < 0) {
                                          return ret;
                                      }
                                  }
                                  addcnt++;
                                  abIdx++;
                              }
                          }
                      }
                  }
                  psrhCache->keyPtr[abPtrIdx + 1] = abIdx;
              } else {
                  nj_charncpy(key_tmp, yomi, 1);
                  key_len = nj_strlen(key_tmp);
  
                  if (psrhCache->keyPtr[abPtrIdx] == psrhCache->keyPtr[abPtrIdx - 1]) {
  
                      psrhCache->keyPtr[abPtrIdx+1] = psrhCache->keyPtr[abPtrIdx-1];
                      endflg = 0x01;
                  } else {
                      endIdx = psrhCache->keyPtr[abPtrIdx];
                      abIdx_old = psrhCache->keyPtr[abPtrIdx - 1];
  
                      if (NJ_GET_CACHEOVER_FROM_SCACHE(psrhCache)) {
                          abIdx = psrhCache->keyPtr[abPtrIdx - 1];
                          psrhCache->keyPtr[abPtrIdx] = abIdx;
                      } else {
                          abIdx = psrhCache->keyPtr[abPtrIdx];
                      }
  
                      if ((abIdx > NJ_SEARCH_CACHE_SIZE) || (abIdx_old >= NJ_SEARCH_CACHE_SIZE)
                          || (endIdx > NJ_SEARCH_CACHE_SIZE)) {
  
                          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_BROKEN);
                      }
  
                      for (m = abIdx_old; m < endIdx; m++) {
                          node = psrhCache->storebuff[m].node;
                          now = psrhCache->storebuff[m].now;
  
                          if ((node == now) && (psrhCache->storebuff[m].idx_no == 0)) {
                              continue;
                          }
                          ret = search_yomi_node(condition->operation,
                                                 node, now, psrhCache->storebuff[m].idx_no,
                                                 key_tmp, key_len, root,
                                                 node_mid, bit_left, bit_data,
                                                 data_top, ytbl_cnt, y, ytbl_top,
                                                 &tmpbuff,
                                                 &con_node, &data_offset);
  
                          if (ret < 0) {
  
                          } else {
  
                              if (abIdx >= NJ_SEARCH_CACHE_SIZE) {
                                  psrhCache->keyPtr[abPtrIdx+1] = 0;
                                  return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_NOT_ENOUGH);
                              }
  
                              psrhCache->storebuff[abIdx] = tmpbuff;
                              now = con_node;
                              psrhCache->storebuff[abIdx].top = data_offset;
  
                              if (condition->operation == NJ_CUR_OP_FORE) {
                                  ret = get_node_bottom(key_tmp, now, node_mid, data_top,
                                                        bit_left, bit_data,
                                                        psrhCache->storebuff[abIdx].top,
                                                        loctset->loct.handle,
                                                        &(psrhCache->storebuff[abIdx].bottom));
  
                                  if (ret < 0) {
                                      return ret;
                                  }
                              }
                              addcnt++;
                              abIdx++;
                          }
  
                          if ((condition->charset != NULL) && aimai_flg) {
  
                              for (l = 0; l < condition->charset->charset_count; l++) {
  
                                  if (nj_charncmp(key, condition->charset->from[l], 1) == 0) {
  
                                      nj_strcpy(char_tmp, condition->charset->to[l]);
  
                                      tmp_len = nj_strlen(char_tmp);
  
                                      node = psrhCache->storebuff[m].node;
                                      now = psrhCache->storebuff[m].now;
                                      ret = search_yomi_node(condition->operation,
                                                             node, now,
                                                             psrhCache->storebuff[m].idx_no,
                                                             char_tmp, tmp_len,
                                                             root, node_mid,
                                                             bit_left, bit_data, data_top,
                                                             ytbl_cnt, y, ytbl_top,
                                                             &tmpbuff,
                                                             &con_node, &data_offset);
  
                                      if (ret < 0) {
  
                                      } else {
  
                                          if (abIdx >= NJ_SEARCH_CACHE_SIZE) {
                                              psrhCache->keyPtr[abPtrIdx+1] = 0;
                                              return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_NOT_ENOUGH);
                                          }
                                          psrhCache->storebuff[abIdx] = tmpbuff;
                                          now = con_node;
  
                                          psrhCache->storebuff[abIdx].top = data_offset;
  
                                          if (condition->operation == NJ_CUR_OP_FORE) {
                                              ret = get_node_bottom(key_tmp, now, node_mid,
                                                                    data_top, bit_left, bit_data,
                                                                    psrhCache->storebuff[abIdx].top,
                                                                    loctset->loct.handle,
                                                                    &(psrhCache->storebuff[abIdx].bottom));
                                              if (ret < 0) {
                                                  return ret;
                                              }
                                          }
                                          addcnt++;
                                          abIdx++;
                                      }
                                  }
                              }
                          }
                      }
                      psrhCache->keyPtr[abPtrIdx + 1] = abIdx;
                  }
              }
          }
          yomi += UTL_CHAR(yomi);
          key  += UTL_CHAR(key);
      }
  
      if ((addcnt == 0) && (psrhCache->keyPtr[yomi_clen - 1] == psrhCache->keyPtr[yomi_clen])) {
          endflg = 0x01;
      }
  
      if (endflg) {
          loctset->loct.status = NJ_ST_SEARCH_END;
          return 0;
      }
  
      loctset->loct.current = 0;
  
      abPtrIdx = condition->yclen;
  
      abIdx = psrhCache->keyPtr[abPtrIdx];
      abIdx_old = psrhCache->keyPtr[abPtrIdx - 1];
      if ((abIdx > NJ_SEARCH_CACHE_SIZE) || (abIdx_old >= NJ_SEARCH_CACHE_SIZE)) {
          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_BROKEN);
      }
  
      if (condition->mode == NJ_CUR_MODE_FREQ) {
          hindo_max = 0;
          hindo_max_data = 0;
          abIdx_current = abIdx_old;
          stem_data = data_top + psrhCache->storebuff[abIdx_current].top;
  
          hindo = (NJ_UINT16) *((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                             get_stem_hindo(loctset->loct.handle, stem_data)));
          hindo_tmp = 0;
          hindo_tmp_data = 0;
          current = 0;
          while (stem_data <= (data_top + psrhCache->storebuff[abIdx_current].bottom)) {
  
              if (hindo > hindo_tmp) {
                  hindo_tmp = hindo;
                  hindo_tmp_data = current;
              }
  
              j = get_stem_next(loctset->loct.handle, stem_data);
              current += j;
              stem_data += j;
  
              hindo = (NJ_UINT16) *((NJ_UINT8 *) (HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                                  get_stem_hindo(loctset->loct.handle, stem_data)));
          }
  
          psrhCache->storebuff[abIdx_current].current = hindo_tmp_data;
          if (hindo_tmp > hindo_max) {
              hindo_max = hindo_tmp;
              hindo_max_data = hindo_tmp_data;
          }
      } else {
          abIdx_current = abIdx_old;
  
          stem_data = data_top + psrhCache->storebuff[abIdx_current].top;
  
          hindo = (NJ_UINT16) *((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                             + get_stem_hindo(loctset->loct.handle, stem_data)));
  
          hindo_max = hindo;
          hindo_max_data = 0;
      }
  
  
      loctset->loct.top = psrhCache->storebuff[abIdx_current].top;
      loctset->loct.bottom = psrhCache->storebuff[abIdx_current].bottom;
  
      loctset->cache_freq = CALCULATE_HINDO(hindo_max, loctset->dic_freq.base,
                                            loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
      loctset->loct.current = hindo_max_data;
      loctset->loct.current_cache = (NJ_UINT8)abIdx_current;
  
      psrhCache->viewCnt = 1;
      NJ_SET_AIMAI_TO_SCACHE(psrhCache);
  
      return 1;
  }
  
  static NJ_INT16 search_yomi_node(NJ_UINT8 operation, NJ_UINT8 *node, NJ_UINT8 *now,
                                   NJ_UINT16 idx_no, NJ_CHAR  *yomi, NJ_UINT16 yomilen,
                                   NJ_UINT8 * root, NJ_UINT8 * node_mid,
                                   NJ_UINT16 bit_left, NJ_UINT16 bit_data,
                                   NJ_UINT8 * data_top,
                                   NJ_INT16 ytbl_cnt, NJ_UINT16 y, NJ_UINT8 * ytbl_top,
                                   NJ_CACHE_INFO * storebuf,
                                   NJ_UINT8 ** con_node,
                                   NJ_UINT32 * data_offset)
  {
      NJ_UINT8 index;
      NJ_UINT8 *wkc;
      NJ_UINT8 *byomi;
      NJ_INT16 idx;
      NJ_INT16 char_size;
      NJ_INT16 left, right, mid;
      NJ_UINT16 c, d;
      NJ_UINT8 c1 = 0, c2 = 0;
      NJ_UINT16 ysize = yomilen * sizeof(NJ_CHAR);
      NJ_UINT16 idx_cnt;
      NJ_UINT16 nd_index;
      NJ_UINT16 data;
      NJ_UINT16 pos, j, bit_all, bit_tmp, bit_idx;
      NJ_UINT32 data_l;
      NJ_UINT8 restart_flg = 0;
  
      *con_node = NULL;
      idx_cnt = 1;
      storebuf->idx_no = 0;
  
      byomi = (NJ_UINT8*)yomi;
  
      while (ysize > 0) {
          if (ytbl_cnt != 0) {
              char_size = UTL_CHAR(byomi) * sizeof(NJ_CHAR);
              if (char_size > 2) {
                  return -1;
              }
  
              if (char_size == 2) {
                  if (y == 1) {
                      return -1;
                  }
                  c1 = *byomi;
                  c2 = *(byomi + 1);
                  c = (NJ_UINT16)((c1 << 8) | c2);
              } else {
  
                  c1 = *byomi;
                  c2 = 0x00;
                  c = (NJ_UINT16)(*byomi);
              }
  
              idx = -1;
              left = 0;
              right = ytbl_cnt;
  
              if (y == 2) {
                  while (left <= right) {
                      mid = (left + right) >> 1;
                      wkc = ytbl_top + (mid << 1);
  
                      if (c1 == *wkc) {
                          if (c2 == *(wkc + 1)) {
                              idx = (NJ_UINT16) (mid + 1);
                              break;
                          }
                          if (c2 < *(wkc + 1)) {
                              right = mid - 1;
                          } else {
                              left = mid + 1;
                          }
                      } else if (c1 < *wkc) {
                          right = mid - 1;
                      } else {
                          left = mid + 1;
                      }
                  }
              } else {
                  while (left <= right) {
                      mid = (left + right) >> 1;
                      wkc = ytbl_top + (mid * y);
                      d = (NJ_UINT16) (*wkc);
                      if (c == d) {
                          idx = (NJ_UINT16) (mid + 1);
                          break;
                      }
                      if (c < d) {
                          right = mid - 1;
                      } else {
                          left = mid + 1;
                      }
                  }
              }
  
              if (idx < 0) {
                  return -1;
              }
              index = (NJ_UINT8) idx;
          } else {
              index = *byomi;
              char_size = 1;
          }
  
          byomi += char_size;
          ysize -= char_size;
  
          while (now < data_top) {
              if (NODE_IDX_EXIST(now)) {
                  bit_idx = 8;
                  idx_cnt = NODE_IDX_CNT(now);
              } else {
                  bit_idx = 4;
                  idx_cnt = 1;
              }
              bit_all = bit_idx;
  
              if (NODE_LEFT_EXIST(now)) {
                  bit_all += bit_left;
              }
  
              if (NODE_DATA_EXIST(now)) {
                  bit_all += bit_data;
              }
              bit_tmp = bit_all;
  
              bit_all += (NJ_UINT16) (idx_no << 3);
  
              pos = (NJ_UINT16) (bit_all >> 3);
  
              data = (NJ_UINT16) (NJ_INT16_READ(now + pos));
  
              j = (NJ_UINT16) (bit_all & 0x0007);
  
              nd_index = GET_BITFIELD_16(data, j, INDEX_BIT);
              if (index == (NJ_UINT8) nd_index) {
                  break;
              } else {
                  if ((!NODE_TERM(now)) && (index > (NJ_UINT8) nd_index) && (idx_no == 0)) {
                      now += GET_BIT_TO_BYTE(bit_tmp + (idx_cnt * 8));
                      if (now == node_mid) {
  
                          return -1;
                      }
                      continue;
                  } else {
                      if ((now == node_mid) && (restart_flg == 0)
                          && (index < (NJ_UINT8) nd_index) && (idx_no == 0)
                          && (root != node_mid)) {
                          now = root;
                          idx_no = 0;
                          restart_flg = 1;
                          continue;
                      }
                      return -1;
                  }
              }
          }
  
          if ( (idx_cnt > (NJ_UINT16) (idx_no + 1))) {
              if (ysize == 0) {
                  if (operation == NJ_CUR_OP_FORE) {
                      storebuf->node = now;
                      storebuf->now = now;
                      storebuf->idx_no = idx_no + 1;
                      node = now;
                      break;
                  }
                  return -2;
              }
              idx_no++;
              continue;
          }
  
          node = now;
          storebuf->node = now;
          idx_no = 0;
  
          if (ysize == 0) {
              *con_node = now;
          } else {
              if (!(NODE_LEFT_EXIST(now))) {
                  return -1;
              }
          }
  
          if (NODE_LEFT_EXIST(now)) {
              if (NODE_IDX_EXIST(now)) {
                  bit_idx = 8;
              } else {
                  bit_idx = 4;
              }
              pos = (NJ_UINT16) (bit_idx >> 3);
              data_l = (NJ_UINT32) (NJ_INT32_READ(now + pos));
  
  
              j = (NJ_UINT16) (bit_idx & 0x0007);
  
              now += GET_BITFIELD_32(data_l, j, bit_left);
              storebuf->now = now;
          } else {
              storebuf->now = now;
          }
      }
  
      if (*con_node == NULL) {
          *con_node = now;
      }
  
      if ((node == NULL) || !(NODE_DATA_EXIST(node))) {
  
          if ((operation == NJ_CUR_OP_FORE) && (node != NULL)) {
              while (!NODE_DATA_EXIST(node)) {
                  if (!(NODE_LEFT_EXIST(node))) {
                      return -2;
                  }
  
                  if (NODE_IDX_EXIST(node)) {
                      bit_idx = 8;
                  } else {
                      bit_idx = 4;
                  }
                  pos = (NJ_UINT16) (bit_idx >> 3);
                  data_l = (NJ_UINT32) (NJ_INT32_READ(node + pos));
  
                  j = (NJ_UINT16) (bit_idx & 0x0007);
                  node += GET_BITFIELD_32(data_l, j, bit_left);
              }
          } else {
              return -2;
          }
      }
  
      if (NODE_IDX_EXIST(node)) {
          bit_idx = 8;
      } else {
          bit_idx = 4;
      }
  
      if (NODE_LEFT_EXIST(node)) {
          bit_all = bit_idx + bit_left;
      } else {
          bit_all = bit_idx;
      }
  
      pos = (NJ_UINT16) (bit_all >> 3);
      data_l = (NJ_UINT32) (NJ_INT32_READ(node + pos));
  
      j = (NJ_UINT16) (bit_all & 0x0007);
      *data_offset = GET_BITFIELD_32(data_l, j, bit_data);
  
      return 1;
  }
  
  static NJ_INT16 get_node_bottom(NJ_CHAR * yomi, NJ_UINT8 * now, NJ_UINT8 * node_mid,
                                  NJ_UINT8 * data_top, NJ_UINT16 bit_left, NJ_UINT16 bit_data,
                                  NJ_UINT32 top, NJ_DIC_HANDLE handle,
                                  NJ_UINT32 * ret_bottom)
  {
      NJ_UINT8 *node;
      NJ_UINT16 idx_cnt;
      NJ_UINT32 data_offset;
      NJ_UINT16 pos, j, bit_all;
      NJ_UINT32 data_l;
      NJ_UINT8 bottom_flg = 0;
      NJ_UINT8 *stem_data;
      NJ_UINT32 bottom, next;
  
      bottom = top;
  
      if (NJ_CHAR_STRLEN_IS_0(yomi)) {
          node = node_mid;
      } else {
          node = now;
          if (NODE_LEFT_EXIST(node)) {
              if (NODE_IDX_EXIST(node)) {
                  bit_all = 8;
              } else {
                  bit_all = 4;
              }
  
              pos = (NJ_UINT16) (bit_all >> 3);
              data_l = (NJ_UINT32) (NJ_INT32_READ(node + pos));
  
              j = (NJ_UINT16) (bit_all & 0x0007);
              node += GET_BITFIELD_32(data_l, j, bit_left);
  
          } else {
              bottom_flg = 1;
          }
      }
  
      if (!bottom_flg) {
          while (node < data_top) {
              if (!NODE_TERM(node)) {
                  if (NODE_IDX_EXIST(node)) {
                      bit_all = 8;
                      idx_cnt = NODE_IDX_CNT(node);
                  } else {
                      bit_all = 4;
                      idx_cnt = 1;
                  }
  
                  if (NODE_LEFT_EXIST(node)) {
                      bit_all += bit_left;
                  }
  
                  if (NODE_DATA_EXIST(node)) {
                      bit_all += bit_data;
                  }
  
                  node += GET_BIT_TO_BYTE(bit_all + (idx_cnt * 8));
              } else {
                  if (!NODE_LEFT_EXIST(node)) {
                      if (NODE_DATA_EXIST(node)) {
                          if (NODE_IDX_EXIST(node)) {
                              bit_all = 8;
                          } else {
                              bit_all = 4;
                          }
                          pos = (NJ_UINT16) (bit_all >> 3);
                          data_l = (NJ_UINT32) (NJ_INT32_READ(node + pos));
  
                          j = (NJ_UINT16) (bit_all & 0x0007);
                          data_offset = GET_BITFIELD_32(data_l, j, bit_data);
  
                          bottom = data_offset;
                          break;
                      } else {
                          return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_DIC_BROKEN);
                      }
                  } else {
                      if (NODE_IDX_EXIST(node)) {
                          bit_all = 8;
                      } else {
                          bit_all = 4;
                      }
  
                      pos = (NJ_UINT16) (bit_all >> 3);
                      data_l = (NJ_UINT32) (NJ_INT32_READ(node + pos));
  
                      j = (NJ_UINT16) (bit_all & 0x0007);
  
                      node += GET_BITFIELD_32(data_l, j, bit_left);
                  }
              }
          }
      }
  
      stem_data = data_top + bottom;
  
      while (!(STEM_TERMINETER(stem_data))) {
          next = get_stem_next(handle, stem_data);
          stem_data += next;
      }
      *ret_bottom = (NJ_UINT32) (stem_data - data_top);
  
      return 1;
  }
  
  static NJ_INT16 bdic_search_fore_data2(NJ_SEARCH_CONDITION *condition, NJ_SEARCH_LOCATION_SET *loctset, NJ_UINT16 hidx)
  {
      NJ_UINT8 *data, *data_top, *bottom, *data_end;
      NJ_INT16 i = 0;
      NJ_INT16 hindo = 0;
      NJ_UINT32 current = loctset->loct.current;
  
      NJ_SEARCH_CACHE *psrhCache = condition->ds->dic[hidx].srhCache;
  
      NJ_UINT16 top_abIdx;
      NJ_UINT16 bottom_abIdx;
      NJ_UINT16 count_abIdx;
      NJ_UINT16 current_abIdx;
      NJ_UINT16 old_abIdx;
      NJ_UINT8 freq_flag = 0;
      NJ_INT16 save_hindo = 0;
      NJ_UINT16 save_abIdx = 0;
      NJ_UINT16 abPtrIdx;
      NJ_UINT16 m;
      NJ_INT16 ret;
      NJ_INT16 loop_check;
  
      NJ_UINT16 abIdx;
      NJ_UINT16 abIdx_old;
      NJ_UINT16 hindo_max, hindo_tmp;
      NJ_UINT32 hindo_max_data, hindo_tmp_data;
      NJ_UINT16 abIdx_current;
  
      if (GET_LOCATION_STATUS(loctset->loct.status) == NJ_ST_SEARCH_NO_INIT) {
          loctset->loct.status = NJ_ST_SEARCH_READY;
          loctset->loct.current_info = CURRENT_INFO_SET;
          return 1;
      }
  
      if (NJ_GET_AIMAI_FROM_SCACHE(psrhCache)) {
          NJ_UNSET_AIMAI_TO_SCACHE(psrhCache);
  
          data_top = STEM_AREA_TOP_ADDR(loctset->loct.handle);
          if (condition->operation == NJ_CUR_OP_FORE) {
              if (condition->ylen) {
  
                  abPtrIdx = condition->yclen;
  
                  abIdx = psrhCache->keyPtr[abPtrIdx];
                  abIdx_old = psrhCache->keyPtr[abPtrIdx - 1];
                  if ((abIdx > NJ_SEARCH_CACHE_SIZE) || (abIdx_old >= NJ_SEARCH_CACHE_SIZE)) {
                      return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_BROKEN);
                  }
  
                  if (condition->mode == NJ_CUR_MODE_FREQ) {
                      hindo_max = 0;
                      hindo_max_data = 0;
                      abIdx_current = abIdx_old;
  
                      for (m = abIdx_old; m < abIdx; m++) {
                          data = data_top + psrhCache->storebuff[m].top;
                          hindo = (NJ_UINT16) *((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                                             get_stem_hindo(loctset->loct.handle, data)));
                          hindo_tmp = 0;
                          hindo_tmp_data = 0;
                          current = 0;
  
                          while (data <= (data_top + psrhCache->storebuff[m].bottom)) {
                              if (hindo > hindo_tmp) {
                                  hindo_tmp = hindo;
                                  hindo_tmp_data = current;
                              }
  
                              i = get_stem_next(loctset->loct.handle, data);
                              current += i;
                              data += i;
  
                              hindo = (NJ_UINT16) *((NJ_UINT8 *) (HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                                                  get_stem_hindo(loctset->loct.handle, data)));
                          }
  
                          psrhCache->storebuff[m].current = hindo_tmp_data;
  
                          if (hindo_tmp > hindo_max) {
                              hindo_max = hindo_tmp;
                              hindo_max_data = hindo_tmp_data;
                              abIdx_current = m;
                          }
                      }
                  } else {
                      abIdx_current = abIdx_old;
  
                      data = data_top + psrhCache->storebuff[abIdx_current].top;
  
                      hindo = (NJ_UINT16) *((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                                         + get_stem_hindo(loctset->loct.handle, data)));
                      hindo_max = hindo;
                      hindo_max_data = 0;
                  }
  
                  loctset->loct.top = psrhCache->storebuff[abIdx_current].top;
                  loctset->loct.bottom = psrhCache->storebuff[abIdx_current].bottom;
                  loctset->cache_freq = CALCULATE_HINDO(hindo_max, loctset->dic_freq.base,
                                                        loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
                  loctset->loct.current = hindo_max_data;
                  loctset->loct.current_cache = (NJ_UINT8)abIdx_current;
  
                  psrhCache->viewCnt = 1;
              } else {
                  data = data_top + loctset->loct.top;
                  hindo = (NJ_UINT16) *((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                                     get_stem_hindo(loctset->loct.handle, data)));
                  hindo_max = hindo;
                  hindo_max_data = 0;
  
                  if (condition->mode == NJ_CUR_MODE_FREQ) {
                      i = get_stem_next(loctset->loct.handle, data);
                      current = i;
                      data += i;
  
                      while (data <= (data_top + loctset->loct.bottom)) {
  
                          hindo = (NJ_UINT16)*((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle) +
                                                            get_stem_hindo(loctset->loct.handle, data)));
                          if (hindo > hindo_max) {
                              hindo_max = hindo;
                              hindo_max_data = current;
                          }
  
                          i = get_stem_next(loctset->loct.handle, data);
                          current += i;
                          data += i;
                      }
                  }
                  loctset->cache_freq = CALCULATE_HINDO(hindo_max,
                                                        loctset->dic_freq.base,
                                                        loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
                  loctset->loct.current = hindo_max_data;
              }
          }
          return 1;
      }
  
      data_top = STEM_AREA_TOP_ADDR(loctset->loct.handle);
  
      data = data_top + loctset->loct.top + loctset->loct.current;
  
      bottom = data_top + loctset->loct.bottom;
  
      if (NJ_GET_DIC_FMT(loctset->loct.handle) == NJ_DIC_FMT_KANAKAN) {
          data_end = loctset->loct.handle
              + NJ_DIC_COMMON_HEADER_SIZE
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_DATA_SIZE)
              + NJ_INT32_READ(loctset->loct.handle + NJ_DIC_POS_EXT_SIZE)
              - NJ_DIC_ID_LEN;
      } else {
          data_end = CAND_IDX_AREA_TOP_ADDR(loctset->loct.handle);
      }
  
      if (condition->mode == NJ_CUR_MODE_FREQ) {
          abPtrIdx = condition->yclen;
  
          bottom_abIdx = psrhCache->keyPtr[abPtrIdx];
          top_abIdx = psrhCache->keyPtr[abPtrIdx - 1];
          if ((bottom_abIdx > NJ_SEARCH_CACHE_SIZE) || (top_abIdx >= NJ_SEARCH_CACHE_SIZE)) {
  
              return NJ_SET_ERR_VAL(NJ_FUNC_NJD_B_SEARCH_WORD, NJ_ERR_CACHE_BROKEN);
          }
  
          count_abIdx = bottom_abIdx - top_abIdx;
          if (!count_abIdx) {
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
          old_abIdx = loctset->loct.current_cache;
  
          loop_check = 0;
  
          ret = bdic_get_next_data(data_top, data_end, loctset, psrhCache, old_abIdx);
  
          if (ret == loctset->cache_freq) {
  
              psrhCache->viewCnt++;
              if (psrhCache->viewCnt <= NJ_CACHE_VIEW_CNT) {
                  loctset->loct.status = NJ_ST_SEARCH_READY;
                  loctset->loct.current_info = CURRENT_INFO_SET;
                  loctset->loct.current = psrhCache->storebuff[old_abIdx].current;
                  loctset->loct.current_cache = (NJ_UINT8)old_abIdx;
                  return 1;
              } else {
                  freq_flag = 1;
                  psrhCache->viewCnt = 0;
              }
          } else {
              if (ret == -1) {
                  loop_check++;
              }
              save_hindo = ret;
              save_abIdx = old_abIdx;
          }
  
          current_abIdx = old_abIdx + 1;
          if (current_abIdx >= bottom_abIdx) {
              current_abIdx = top_abIdx;
          }
  
          while (loop_check != count_abIdx) {
              ret = bdic_get_word_freq(data_top, loctset, psrhCache, current_abIdx);
              if ((ret == loctset->cache_freq) &&
                  (loctset->loct.top == psrhCache->storebuff[current_abIdx].top) &&
                  (loctset->loct.current == psrhCache->storebuff[current_abIdx].current)) {
                  ret = bdic_get_next_data(data_top, data_end, loctset, psrhCache, current_abIdx);
              }
  
              if (ret == loctset->cache_freq) {
                  loctset->loct.status = NJ_ST_SEARCH_READY;
                  loctset->loct.current_info = CURRENT_INFO_SET;
                  loctset->loct.top = psrhCache->storebuff[current_abIdx].top;
                  loctset->loct.bottom = psrhCache->storebuff[current_abIdx].bottom;
                  loctset->loct.current = psrhCache->storebuff[current_abIdx].current;
                  loctset->loct.current_cache = (NJ_UINT8)current_abIdx;
                  psrhCache->viewCnt = 1;
                  return 1;
              } else {
                  if (ret == -1) {
                      loop_check++;
                  }
                  if (save_hindo < ret) {
                      save_hindo = ret;
                      save_abIdx = current_abIdx;
                  }
              }
  
              current_abIdx++;
              if (current_abIdx >= bottom_abIdx) {
                  current_abIdx = top_abIdx;
              }
  
              if (current_abIdx == old_abIdx) {
                  if (freq_flag == 1) {
                      loctset->loct.status = NJ_ST_SEARCH_READY;
                      loctset->loct.current_info = CURRENT_INFO_SET;
                      loctset->loct.top = psrhCache->storebuff[current_abIdx].top;
                      loctset->loct.bottom = psrhCache->storebuff[current_abIdx].bottom;
                      loctset->loct.current = psrhCache->storebuff[current_abIdx].current;
                      loctset->loct.current_cache = (NJ_UINT8)current_abIdx;
                      psrhCache->viewCnt = 1;
                      return 1;
                  } else if (save_hindo != -1) {
                      loctset->cache_freq = save_hindo;
                      loctset->loct.status = NJ_ST_SEARCH_READY;
                      loctset->loct.current_info = CURRENT_INFO_SET;
                      loctset->loct.top = psrhCache->storebuff[save_abIdx].top;
                      loctset->loct.bottom = psrhCache->storebuff[save_abIdx].bottom;
                      loctset->loct.current = psrhCache->storebuff[save_abIdx].current;
                      loctset->loct.current_cache = (NJ_UINT8)save_abIdx;
                      psrhCache->viewCnt = 1;
                      return 1;
                  }
              }
          }
      } else {
  
          i = get_stem_next(loctset->loct.handle, data);
          data += i;
          current += i;
  
          if (data > bottom) {
              loctset->loct.status = NJ_ST_SEARCH_END;
              return 0;
          }
  
          hindo = (NJ_INT16)*((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                           + get_stem_hindo(loctset->loct.handle, data)));
          loctset->cache_freq = CALCULATE_HINDO(hindo, loctset->dic_freq.base,
                                                loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
          loctset->loct.status = NJ_ST_SEARCH_READY;
          loctset->loct.current_info = CURRENT_INFO_SET;
          loctset->loct.current = current;
          return 1;
      }
  
      loctset->loct.status = NJ_ST_SEARCH_END;
      return 0;
  }
  
  static NJ_INT16 bdic_get_next_data(NJ_UINT8 *data_top, NJ_UINT8 *data_end,
                                     NJ_SEARCH_LOCATION_SET *loctset,
                                     NJ_SEARCH_CACHE *psrhCache,
                                     NJ_UINT16 abIdx)
  {
      NJ_UINT8 *data, *bottom;
      NJ_INT16 i = 0;
      NJ_INT16 hindo = 0;
      NJ_INT16 hindo_max = -1;
      NJ_UINT8 no_hit = 0;
      NJ_UINT32 current = psrhCache->storebuff[abIdx].current;
      NJ_UINT8 *current_org;
      NJ_UINT32 hindo_data = 0;
      NJ_INT16 freq_org = loctset->cache_freq;
  
  
      if (psrhCache->storebuff[abIdx].current == LOC_CURRENT_NO_ENTRY) {
          return (-1);
      }
  
      data = data_top + psrhCache->storebuff[abIdx].top + psrhCache->storebuff[abIdx].current;
  
      current_org = data;
  
      bottom = data_top + psrhCache->storebuff[abIdx].bottom;
  
      while (data < data_end) {
          i = get_stem_next(loctset->loct.handle, data);
          data += i;
          current += i;
  
          if (data > bottom) {
              if ((freq_org == 0) || (no_hit == 1)) {
                  psrhCache->storebuff[abIdx].current = LOC_CURRENT_NO_ENTRY;
                  return -1;
              }
  
              freq_org -= 1;
  
              data = data_top + psrhCache->storebuff[abIdx].top;
              current = 0;
  
              no_hit = 1;
          }
  
          if ((hindo_max != -1) && (data == current_org)) {
              psrhCache->storebuff[abIdx].current = hindo_data;
              return hindo_max;
          }
  
          hindo = (NJ_INT16)*((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                           + get_stem_hindo(loctset->loct.handle, data)));
  
          hindo = CALCULATE_HINDO(hindo, loctset->dic_freq.base, loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
  
          if (hindo == freq_org) {
              psrhCache->storebuff[abIdx].current = current;
              return hindo;
          }
  
          if (hindo < freq_org) {
              if ((hindo > hindo_max) || ((hindo == hindo_max) && (current < hindo_data))) {
                  hindo_max = hindo;
                  hindo_data = current;
              }
          }
      }
  
      psrhCache->storebuff[abIdx].current = LOC_CURRENT_NO_ENTRY;
      return -1;
  }
  
  static NJ_INT16 bdic_get_word_freq(NJ_UINT8 * data_top, NJ_SEARCH_LOCATION_SET * loctset,
                                     NJ_SEARCH_CACHE * psrhCache, NJ_UINT16 abIdx)
  {
      NJ_UINT8 *data;
      NJ_INT16 hindo = 0;
  
      if (psrhCache->storebuff[abIdx].current != LOC_CURRENT_NO_ENTRY) {
          data = data_top + psrhCache->storebuff[abIdx].top + psrhCache->storebuff[abIdx].current;
  
          hindo = (NJ_INT16)*((NJ_UINT8 *)(HINDO_NO_TOP_ADDR(loctset->loct.handle)
                                           + get_stem_hindo(loctset->loct.handle, data)));
  
          hindo = CALCULATE_HINDO(hindo, loctset->dic_freq.base, loctset->dic_freq.high, COMP_DIC_FREQ_DIV);
  
      } else {
          hindo = -1;
      }
  
      return hindo;
  }
  