// PDicReader.cpp: CPDicReader クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// // 2007/03/21 hishida #include "stdafx.h" #include "PDicReader.h" #ifdef _WIN32_WCE #include "FileIO.h" #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #define _KANJI_CP 932 #define _DEF_RELEASECONTROL 1 ////////////////////////////////////////////////////////////////////// // 覚え書き ////////////////////////////////////////////////////////////////////// /* Unicode版のコンパイル指定 ------------------------------------------------------------ MBCS Unicode ------------------------------------------------------------ エントリポイントシンボル 無し wWinMainCRTStartup プリプロセッサの定義 _MBCS _UNICODE,UNICODE ------------------------------------------------------------ */ /* PDICのデータ構造 ヘッダー部 (256) 拡張ヘッダー部(可変長:現在0) インデックス部(可変長:256単位) データ部 (可変長:256単位) インデックスの開始位置 = ヘッダ長(256) NEWDIC2(3.0) (ディスク上の位置)=(ヘッダーサイズ) +(インデックスサイズ) +(データブロック長)*(物理ブロック番号) NEWDIC3(4.0) (ディスク上の位置)=(ヘッダーサイズ) +(拡張ヘッダーサイズ) +(インデックスブロック数)*(ブロックサイズ) +(ブロックサイズ)*(物理ブロック番号) (ディスクの位置)=(header_size) +(extheader) +(index_block)*(block_size) +(block_size)×(物理ブロック番号) ※ブロックサイズは256 dictype & 0x08 ならUnicode */ // BOCU-1からUCS2への変換 int BOCU1_decode( byte*p, // in:BOCU-1 int length, // in:入力文字列のバイト数 WCHAR*dest, // out:UCS2への変換先 int maxdest ) // in:destの最大長 { ASSERT( p ); ASSERT( dest ); Bocu1Rx rx={ 0, 0, 0 }; int32_t c, i, sLength; WCHAR* destorg = dest; i = sLength = 0; while( i=0) { *dest++ = c; } } *dest = '\0'; return sLength; } #if defined(UNICODE) // 単純サーチ(UTF-16) int SearchString( WCHAR* textstr, int textlen, WCHAR* keyword, int keywordlen ) { WCHAR *wbp; for ( wbp = textstr; wbp<=textstr+textlen-keywordlen; ++wbp ) { if ( _tcsncmp( wbp, keyword, keywordlen ) == 0 ) { return wbp - textstr; } } return -1; } #endif // 単純サーチ(バイト列) int SearchString( byte* textstr, int textlen, byte* keyword, int keywordlen ) { byte *bp; for ( bp = textstr; bp<=textstr+textlen-keywordlen; ++bp ) { if ( strncmp( (char*)bp, (char*)keyword, keywordlen ) == 0 ) { return bp - textstr; } } return -1; } #define _BM_SEARCH 1 // 全文検索はBM法で実行 #if defined(_BM_SEARCH) #define CSIZE 256 // byte 単位で比較を行う // 移動量テーブルの作成 // byte bm_table[CSIZE]; void make_bm_table( byte *pattern, // 検索文字列 int size , // 検索文字列長 byte *bm_table // 移動量テーブル(配列長はCSIZE) ) { int i; for( i=0; i0 ); //検索エンジン int i; unsigned char c, tail; if ( pattern == NULL ) return -1; tail = pattern[ patlen -1 ]; // 最後の文字 int Index = 0; if( patlen == 1 ) { // 検索文字列の長さが1の場合 while(1) { if( Index > bufLen ) { return -1; } if( (buffer[Index] ) == tail ) { return Index; } Index++; } } else { // 検索文字列の長さが2以上の場合 Index += (patlen-1); // 検索開始ポインタを検索文字列の最後の文字にセット while(1) { // 検索開始 if( Index > bufLen ) { //見つからなかった return -1; } c = buffer[Index]; if( c == tail ) { for( i=1; i> 8; if ( m_pdic_ver < 4 || m_header.header_size == 0 || m_header.header_size > PDIC_MAX_HEADER_LEN || m_header.block_size == 0 || m_header.block_size > PDIC_MAX_BLKLEN ) { goto header_error; } if ( memcmp( (char*)PDIC_MAGIC_STR, (char*)m_header.headername+0x0D, sizeof(PDIC_MAGIC_STR)-1 )==0 // PDIC/Unicode || memcmp( (char*)PDIC_MAGIC_STR, (char*)m_header.headername+0x18, sizeof(PDIC_MAGIC_STR)-1 )==0 // PDIC for win32 ) { ; } else { goto header_error; } // バージョンによって項目のオフセットが異なるので、調整を行う。 // ver.5 を仮定しているので、ver.5の場合は調整なし // なお、nindex,nblockは使用せず、nindex2,nblock2を使う switch ( m_pdic_ver ) { case 2: m_header.nindex2 = m_header.nindex; m_header.nblock2 = m_header.nblock; m_header.extheader = 0; m_header.index_blkbit = 0; // 16 bit m_header.empty_block2 = m_header.empty_block; break; case 3: m_header.nindex2 = m_header.nindex; m_header.nblock2 = m_header.nblock; m_header.extheader = 0; m_header.index_blkbit = 0; // 16 bit m_header.block_size *=16; // NEWDIC2の場合、16で割った数が入っている m_header.empty_block2 = m_header.empty_block; break; case 4: m_header.olenumber = LFOURBYTEUINT(buffer+167); m_header.os = buffer[171]; m_header.extheader = LFOURBYTEUINT(buffer+182); m_header.empty_block2 = LFOURBYTEUINT(buffer+186); m_header.nindex2 = LFOURBYTEUINT(buffer+190); m_header.nblock2 = LFOURBYTEUINT(buffer+194); m_header.index_blkbit = buffer[198]; m_header.update_count = LFOURBYTEUINT(buffer+208); break; case 5: break; } m_pIndex = new CPDicIndex( m_fp, &m_header ); m_pData = new CPDicData( m_fp, &m_header ); m_bOpened = 1; return 0; header_error: Close(); return -1; } // PDIC 辞書のファイルハンドルのみ再open // 0 正常 // -1 失敗 int CPDicReader::ReOpen( LPCTSTR pszFilePath ) { ASSERT( pszFilePath ); if ( !m_bOpened || !m_fp ) return -1; fclose( m_fp ); // PDIC辞書ファイルをopenする m_fp = _tfopen( pszFilePath, _T("rb") ); if ( !m_fp ) { return -1; } if ( m_pData ) m_pData->m_fp = m_fp; if ( m_pIndex ) m_pIndex->m_fp = m_fp; return 0; } // PDIC 辞書の使用を終了する void CPDicReader::Close() { if ( m_fp ) { fclose( m_fp ); m_fp = NULL; } if ( m_pIndex ) { delete m_pIndex; m_pIndex = NULL; } if ( m_pData ) { delete m_pData; m_pData = NULL; } // 検索構造 ClearHitEnt(); m_bOpened = 0; } void CPDicReader::ClearHitEnt() { // 検索結果をクリア if ( m_hitent ) { free( m_hitent ); m_hitent = NULL; } if ( m_title_pool ) { free( m_title_pool ); m_title_pool = NULL; } m_numhit = 0; // ヒット数 m_max_hitent = 0; // m_hitent[]の割当サイズ m_max_title_pool = 0; // m_title_poolの割当サイズ m_title_len = 0; // m_title_poolの最終書込位置 } // PDIC Unicode検索語の正規化 // カタカナのみ清音化している WCHAR fromPDICTbl[] = { // hira dakuon /* 0x304C, 0x304E, 0x3050, 0x3052, 0x3054, // ga gi gu ge go 0x3056, 0x3058, 0x305A, 0x305C, 0x305E, // za zi zu ze zo 0x3060, 0x3062, 0x3065, 0x3067, 0x3069, // da di du de do 0x3070, 0x3073, 0x3076, 0x3079, 0x307C, // ba bi bu be bo 0x3071, 0x3074, 0x3077, 0x307A, 0x307D, // pa pi pu pe po 0x3041, 0x3043, 0x3045, 0x3047, 0x3049, // xa xi xu xe xo 0x3063, // xtu 0x3083, 0x3085, 0x3087, // xya xyu xyo 0x308E, 0x3095, 0x3096, // xwa xka xke */ // kata dakuon 0x30AC, 0x30AE, 0x30B0, 0x30B2, 0x30B4, // ga gi gu ge go 0x30B6, 0x30B8, 0x30BA, 0x30BC, 0x30BE, // za zi zu ze zo 0x30C0, 0x30C2, 0x30C5, 0x30C7, 0x30C9, // da di du de do 0x30D0, 0x30D3, 0x30D6, 0x30D9, 0x30DC, // ba bi bu be bo 0x30D1, 0x30D4, 0x30D7, 0x30DA, 0x30DD, // pa pi pu pe po 0x30A1, 0x30A3, 0x30A5, 0x30A7, 0x30A9, // xa xi xu xe xo 0x30C3, // xtu 0x30E3, 0x30E5, 0x30E7, // xya xyu xyo 0x30EE, 0x30F5, 0x30F6, // xwa xka xke }; WCHAR toPDICTbl[] = { // hira seion /* 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, // ka ki ku ke ko 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // sa si su se so 0x305F, 0x3061, 0x3064, 0x3066, 0x3068, // ta ti tu te to 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho 0x306F, 0x3072, 0x3075, 0x3078, 0x307B, // ha hi hu he ho 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, // a i u e o 0x3064, // tu 0x3084, 0x3086, 0x3088, // ya yu yo 0x308F, 0x304B, 0x3051, // wa ka ke */ // kata seion 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, // ka ki ku ke ko 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, // sa si su se so 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, // ta ti tu te to 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, // ha hi hu he ho 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, // a i u e o 0x30C4, // tu 0x30E4, 0x30E6, 0x30E8, // ya yu yo 0x30EF, 0x30AB, 0x30B1, // wa ka ke }; WCHAR normalizePDIC( WCHAR uch ) { WCHAR xch = 0; int ix; int imax = sizeof(fromPDICTbl) / sizeof(WCHAR); for ( ix=0;ix= 6 ) { // Unicode版の場合、検索語の正規化 // (1)英字の小文字化 // (2)カタカナ半濁音、濁音、拗音の清音化 int ix; int klen = _tcslen(keyword); for ( ix=0;ix='A' && keyword[ix]<='Z' ) { wcNrmSearchWord[ix] = keyword[ix]+('a'-'A'); } else if ( keyword[ix] == '-' ) { wcNrmSearchWord[ix] = ' '; } else if ( xch = normalizePDIC( keyword[ix] ) ) { wcNrmSearchWord[ix] = xch; } else { wcNrmSearchWord[ix] = keyword[ix]; } } wcNrmSearchWord[ix] = 0; keyword = wcNrmSearchWord; } #endif unsigned long _datablk; // データブロックの物理ブロック番号 byte _titlestr[PDIC_MAX_TITLE+1]; // インデックスに記録された見出し語 #if defined(UNICODE) TCHAR w_titlestr[PDIC_MAX_TITLE+1]; byte mb_keyword[PDIC_MAX_TITLE+1]; int nChar; #endif int keywordlen; int _titlelen,_hoffs,_honbunlen,_yoffs,_yoreilen,_poffs,_phoneticlen,_level; m_numhit = 0; *over = false; // if ( maxHit == 0 ) { // maxHit = PDIC_MAX_HIT; // } // 検索結果をクリア ClearHitEnt(); // (1)先頭のインデックス番号を見つける long _idxno = m_pIndex->BSearchIndex( keyword ); // (2)インデックスブロックをもとにデータブロックを順に読む int _over = 0; int status; #if defined(UNICODE) if ( m_header.dictype & 0x08 ) { // BOCU1 keywordlen = _tcslen(keyword); } else { nChar = ::WideCharToMultiByte( _KANJI_CP, NULL, keyword, _tcslen(keyword), (LPSTR)mb_keyword, PDIC_MAX_TITLE, NULL, NULL); // 変換(→ShiftJIS) mb_keyword[nChar] = '\0'; keywordlen = nChar; } #else keywordlen = _tcslen(keyword); #endif // 次のインデックスを読む while ( !_over && _idxnoReadRec( _idxno, &_datablk, (byte*)_titlestr, &_titlelen ) == 0 ) { //////////////////////////////////////////////////// // 以下はdicorder == 0 (コード順)の場合用 //////////////////////////////////////////////////// #if defined(UNICODE) // Unicode辞書の時、BOCU->UCS2に変換後比較する if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( _titlestr, _titlelen, w_titlestr, PDIC_MAX_TITLE ); status = _tcsncmp( w_titlestr, keyword, keywordlen ) ; } else { // 非Unicode辞書の場合、ShiftJISで比較する status = strncmp( (char*)_titlestr, (char*)mb_keyword, keywordlen ) ; } #else status = strncmp( (char*)_titlestr, keyword, keywordlen ) ; #endif if ( status > 0 ) { // キーワードを超えたので探索終了 _over = 1; break; } // _datablkから始まるデータブロック(連続ブロック)を読む if ( m_pData->ReadBlks( _datablk ) == -1 ) { break; } int _num = 0; // 連続ブロック中のデータレコードを読む while ( !_over ) { int _recOffs = m_pData->GetOffs(); if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level ) != 0 ) { break; } int _strlen; #if defined(UNICODE) // Unicode辞書の時、BOCU->UCS2に変換後比較する if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( _titlestr, _titlelen, w_titlestr, PDIC_MAX_TITLE ); // PDIC/Unicode 対応 ; 検索文字列\t表示文字列 if ( bExact && m_pdic_ver >= 6 ) { int ix; for ( ix=0;ix keywordlen ) { _over = 1; } } else if ( status < 0 ) { // // 検索語よりも手前なので、スキップ } else if ( status > 0 ) { // キーワードを超えたので探索終了 _over = 1; break; } ++_num; // 検索上限が設定されていて件数が超える場合は、検索中止 if ( maxHit>0 && m_numhit>=(unsigned long)maxHit ) { _over = 1; *over = true; } } ++_idxno; } return m_numhit; } // 指定したインデックス番号の示すデータブロックを全て検索 int CPDicReader::SearchAbs( unsigned long idxno ) { unsigned long _datablk; // データブロックの物理ブロック番号 byte _titlestr[PDIC_MAX_TITLE+1]; // インデックスに記録された見出し語 int _titlelen,_hoffs,_honbunlen,_yoffs,_yoreilen,_poffs,_phoneticlen,_level; // 検索結果をクリア ClearHitEnt(); // インデックスブロックをもとにデータブロックを順に読む int _over = 0; // 次のインデックスを読む if ( idxno<(unsigned long)m_header.nindex2 && m_pIndex->ReadRec( idxno, &_datablk, (byte*)_titlestr, &_titlelen ) == 0 && m_pData->ReadBlks( _datablk ) == 0 ) { int _num = 0; // 連続ブロック中のデータレコードを読む while ( !_over ) { int _recOffs = m_pData->GetOffs(); if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level ) != 0 ) { break; } // 検索結果テーブルが未割当なら、ここで割り当て // サイズが不足する場合、拡張 if ( !m_hitent ) { m_max_hitent = MAX_PDIC_HITENT; m_hitent = (PDIC_HITENT*)malloc( m_max_hitent * sizeof(PDIC_HITENT) ); } else if ( m_max_hitent <= m_numhit ) { m_max_hitent += MAX_PDIC_HITENT; m_hitent = (PDIC_HITENT*)realloc( m_hitent, m_max_hitent * sizeof(PDIC_HITENT) ); } // 見出し語は、見出し語プールに保存する if ( !m_title_pool ) { m_max_title_pool = MAX_PDIC_POOL; m_title_pool = (byte*)malloc( m_max_title_pool * sizeof(byte) ); } else if ( m_max_title_pool <= m_title_len+_titlelen+1 ) { m_max_title_pool += MAX_PDIC_POOL; m_title_pool = (byte*)realloc( m_title_pool, m_max_title_pool * sizeof(byte) ); } // 検索結果テーブルに登録する memset( &m_hitent[m_numhit] ,0, sizeof(PDIC_HITENT) ); m_hitent[m_numhit].indexno = idxno; m_hitent[m_numhit].blkno = _datablk; m_hitent[m_numhit].titleoffs = m_title_len; m_hitent[m_numhit].titlelen = _titlelen; m_hitent[m_numhit].hoffs = _hoffs; m_hitent[m_numhit].honbunlen = _honbunlen; m_hitent[m_numhit].yoffs = _yoffs; m_hitent[m_numhit].yoreilen = _yoreilen; m_hitent[m_numhit].poffs = _poffs; m_hitent[m_numhit].phoneticlen = _phoneticlen; m_hitent[m_numhit].level = _level; m_hitent[m_numhit].recOffs = _recOffs; // m_hitent[m_numhit].num = _num; memcpy( m_title_pool+m_title_len,_titlestr,_titlelen ); m_title_len += _titlelen; m_title_pool[m_title_len++] = '\0'; ++m_numhit; ++_num; } } return m_numhit; } #if defined(_DEF_RELEASECONTROL) void ReleaseControl(); #else // 制御をシステムに返す void ReleaseControl() { MSG message; if ( ::PeekMessage(&message,NULL,0,0,PM_REMOVE)) { ::TranslateMessage(&message); ::DispatchMessage(&message); } Sleep( 0 ); // 同じ優先順位のスレッドがあれば処理を譲る } #endif // 全文検索 int CPDicReader::SearchFullText( LPCTSTR keyword, // 検索キーワード int maxHit, // 検索一致数上限; 0 は無制限 int *over, // 上限を超えた場合、1を設定 short *bAbort, // 中断フラグ void ( *EchoCallback )(LPVOID pParam,int count, int blks, int nRead ), // 表示コールバック LPVOID pParam, // コールバック関数に引き渡すcallerのオブジェクト int flag // 検索対象フラグ PDIC_S_TITLE | PDIC_S_HONBUN | PDIC_S_YOREI ) { ASSERT( keyword ); byte _titlestr[PDIC_MAX_TITLE+1]; // インデックスに記録された見出し語 #if defined(UNICODE) TCHAR w_honbun[PDIC_MAX_HONBUN+1]; TCHAR w_titlestr[PDIC_MAX_TITLE+1]; byte mb_keyword[PDIC_MAX_TITLE+1]; int nChar; int _strlen; #endif int keywordlen; int _titlelen,_hoffs,_honbunlen,_yoffs,_yoreilen,_poffs,_phoneticlen,_level; m_numhit = 0; *over = false; // if ( maxHit == 0 ) { // maxHit = PDIC_MAX_HIT; // } // 検索結果をクリア ClearHitEnt(); // (1)先頭に位置づける m_seq_idxno = 0; // (2)インデックスブロックをもとにデータブロックを順に読む int _over = 0; int status; #if defined(UNICODE) if ( m_header.dictype & 0x08 ) { // BOCU1 keywordlen = _tcslen(keyword); } else { nChar = ::WideCharToMultiByte( _KANJI_CP, NULL, keyword, _tcslen(keyword), (LPSTR)mb_keyword, PDIC_MAX_TITLE, NULL, NULL); // 変換(→ShiftJIS) mb_keyword[nChar] = '\0'; keywordlen = nChar; } #else keywordlen = _tcslen(keyword); #endif // 次のインデックスを読む while ( !_over && m_seq_idxno<(unsigned long)m_header.nindex2 && m_pIndex->ReadRec( m_seq_idxno, &m_seq_datablk, (byte*)_titlestr, &_titlelen ) == 0 ) { // _datablkから始まるデータブロック(連続ブロック)を読む if ( m_pData->ReadBlks( m_seq_datablk ) == -1 ) { break; } int _num = 0; // 連続ブロック中のデータレコードを読む while ( !_over ) { int _recOffs = m_pData->GetOffs(); // 次のレコードを読む if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level)!= 0 ) { // データブロック内の最後のレコードの場合、次のデータブロックを読む // インデックスから、次のデータブロックを得る ++m_seq_idxno; if ( m_pIndex->ReadRec( m_seq_idxno, &m_seq_datablk, (byte*)_titlestr,&_titlelen ) != 0 ) { break; } // 次のデータブロックを読む if ( m_pData->ReadBlks( m_seq_datablk ) != 0 ) { break; } // 次のレコードを読む _recOffs = m_pData->GetOffs(); if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level )!= 0 ) { break; } } byte* p = m_pData->GetBuffer(); if ( !p ) break; if ( EchoCallback ) EchoCallback( pParam, m_numhit, m_header.nindex2,m_seq_idxno ); ReleaseControl(); if ( *bAbort ) { _over = 1; break; } #if defined(_BM_SEARCH) byte bm_table[CSIZE]; #if defined(UNICODE) if ( m_header.dictype & 0x08 ) { // BOCU1 make_bm_table( (byte*)keyword, keywordlen*sizeof(WCHAR) ,bm_table); } else { make_bm_table( mb_keyword, keywordlen ,bm_table); } #else make_bm_table( (byte*)keyword, keywordlen , bm_table); #endif #endif status = -1; // 一致すれば0 // (1)見出しを全文検索 if ( flag & PDIC_S_TITLE ) { #if defined(UNICODE) // Unicode辞書の時、BOCU->UCS2に変換後比較する if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( _titlestr, _titlelen, w_titlestr, PDIC_MAX_TITLE ); _strlen = _tcslen( w_titlestr ); #if defined(_BM_SEARCH) if ( bm_search( (byte*)w_titlestr,_strlen*sizeof(WCHAR), (byte*)keyword, keywordlen*sizeof(WCHAR),bm_table ) != -1 ) { #else if ( SearchString( w_titlestr,_strlen, (WCHAR*)keyword, keywordlen ) != -1 ) { #endif status = 0; } } else { // 非Unicode辞書の場合、ShiftJISで比較する #if defined(_BM_SEARCH) if ( bm_search( _titlestr,_titlelen, mb_keyword, keywordlen,bm_table ) != -1 ) { #else if ( SearchString( _titlestr,_titlelen, mb_keyword, keywordlen ) != -1 ) { #endif status = 0; } } #else #if defined(_BM_SEARCH) if ( bm_search( _titlestr,_titlelen, (byte*)keyword, keywordlen,bm_table ) != -1 ) { #else if ( SearchString( _titlestr,_titlelen, keyword, keywordlen ) != -1 ) { #endif status = 0; } #endif } // (2)本文を全文検索 if ( status != 0 && ( flag & PDIC_S_HONBUN ) && _honbunlen>0 ) { // #if defined(UNICODE) // Unicode辞書の時、BOCU->UCS2に変換後比較する if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( p+_hoffs, _honbunlen, w_honbun, PDIC_MAX_HONBUN ); _strlen = _tcslen( w_honbun ); ASSERT(_strlen0 ) { // #if defined(UNICODE) // Unicode辞書の時、BOCU->UCS2に変換後比較する if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( p+_yoffs, _yoreilen, w_honbun, PDIC_MAX_HONBUN ); _strlen = _tcslen( w_honbun ); ASSERT(_strlen0 && m_numhit>=(unsigned long)maxHit ) { _over = 1; *over = true; } } ++m_seq_idxno; } return m_numhit; } // 0 正常 // -1 失敗 int CPDicReader::GetHitEnt( PDIC_HITENT **hit_list, int *numhit ) { if ( !m_hitent ) { *numhit = 0; return -1; } *hit_list = m_hitent; *numhit = m_numhit; return 0; } // 検索一致個数を返す int CPDicReader::GetHitCount() { return m_numhit; } byte* CPDicReader::GetTextPool() { return m_title_pool; } int CPDicReader::GetMaxText() { return m_title_len; } unsigned long CPDicReader::GetOffs() { return m_pData->GetOffs(); } unsigned long CPDicReader::GetBlkNo() // 現在の連続ブロック先頭番号 { return m_pData->GetBlkNo(); } unsigned long CPDicReader::GetIndexNo() // 現在のインデックス番号 { return m_seq_idxno; } NEWDIC3_5 *CPDicReader::GetHeader() // PDIC辞書のヘッダ情報(Ver5形式) { return &m_header; } // PDIC辞書のバージョン番号 int CPDicReader::GetPDICVer() { return m_pdic_ver; } // num番目の検索結果を取得する。 // 読出領域は、呼び出し元で確保する。 // 見出し語 248字 // 訳語 3000字 // 用例 20000字 // 0 正常 // -1 失敗 int CPDicReader::ReadResult( int num, // 指定した番号の検索結果を取得 LPTSTR title, // 見出し語(unicodeの場合、UCS-2) int maxtitle, // 見出し語の領域の最大長(max:1024) LPTSTR honbun, // 訳語(unicodeの場合、UCS-2) int maxhonbun, // 訳語の領域の最大長(max:3000) LPTSTR yorei, // 用例(unicodeの場合、UCS-2) int maxyorei, // 用例の領域の最大長(max:20000) LPTSTR phonetic, // 発音(unicodeの場合、UCS-2) int maxphonetic, // 発音の領域の最大長(max:1000) int*level, // 単語レベル unsigned short (*phoneticUniMap)[256][2] ) { ASSERT ( num>=0 && num<(int)m_numhit ) ; if ( num<0 || num>=(int)m_numhit ) return -1; if ( !m_hitent ) return -1; if ( !m_title_pool ) return -1; return ReadResultEnt( &m_hitent[num], m_title_pool, title, // 見出し語(unicodeの場合、UCS-2) maxtitle, honbun, // 訳語(unicodeの場合、UCS-2) maxhonbun, // 訳語の領域の最大長(max:3000) yorei, // 用例(unicodeの場合、UCS-2) maxyorei, // 用例の領域の最大長(max:20000) phonetic, // 発音(unicodeの場合、UCS-2) maxphonetic, // 発音の領域の最大長(max:1000) level, // 単語レベル phoneticUniMap ); } // 読出領域は、呼び出し元で確保する。 // 見出し語 248字 // 訳語 3000字 // 用例 20000字 // 0 正常 // -1 失敗 int CPDicReader::ReadResultEnt( PDIC_HITENT*pHitEnt, byte*pTitlePool, LPTSTR title, // 見出し語(unicodeの場合、UCS-2) int maxtitle, // 見出し語の領域の最大長(max:1024) LPTSTR honbun, // 訳語(unicodeの場合、UCS-2) int maxhonbun, // 訳語の領域の最大長(max:3000) LPTSTR yorei, // 用例(unicodeの場合、UCS-2) int maxyorei, // 用例の領域の最大長(max:20000) LPTSTR phonetic, // 発音(unicodeの場合、UCS-2) int maxphonetic, // 発音の領域の最大長(max:1000) int*level, // 単語レベル unsigned short (*phoneticUniMap)[256][2] ) { ASSERT( title ); ASSERT( honbun ); ASSERT( yorei ); title[0] = '\0'; honbun[0] = '\0'; yorei[0] = '\0'; phonetic[0] = '\0'; if ( m_pData->ReadBlks( pHitEnt->blkno ) != 0 ) return -1; byte* p = m_pData->GetBuffer(); if ( !p ) return -1; #if defined(UNICODE) // Unicode辞書の場合、BOCU1->UCS2 if ( m_header.dictype & 0x08 ) { // BOCU1 BOCU1_decode( pTitlePool+pHitEnt->titleoffs,pHitEnt->titlelen, title, maxtitle ); BOCU1_decode( p+pHitEnt->hoffs,pHitEnt->honbunlen, honbun, maxhonbun ); if ( pHitEnt->yoreilen>0 ) { BOCU1_decode( p+pHitEnt->yoffs,pHitEnt->yoreilen, yorei, maxyorei ); } if ( pHitEnt->phoneticlen>0 ) { if ( phoneticUniMap /*&& m_pdic_ver < 6*/ ) { TCHAR tmp_phonetic[PDIC_MAX_PHONETIC+1]; BOCU1_decode( p+pHitEnt->poffs,pHitEnt->phoneticlen, tmp_phonetic, maxphonetic ); MapPhoneticUni( tmp_phonetic,_tcslen(tmp_phonetic), phonetic, maxphonetic,phoneticUniMap ); } else { BOCU1_decode( p+pHitEnt->poffs,pHitEnt->phoneticlen, phonetic, maxphonetic ); } } } else { // 非Unicode辞書の場合、ShiftJIS->UCS2 int nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)pTitlePool+pHitEnt->titleoffs, // マップ元文字列のアドレス pHitEnt->titlelen, // マップ元文字列のバイト数 title, // マップ先ワイド文字列を入れるバッファのアドレス maxtitle // バッファのサイズ ); title[nChar] = 0; nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)p+pHitEnt->hoffs, // マップ元文字列のアドレス pHitEnt->honbunlen, // マップ元文字列のバイト数 honbun, // マップ先ワイド文字列を入れるバッファのアドレス maxhonbun // バッファのサイズ ); honbun[nChar] = 0; if ( pHitEnt->yoreilen>0 ) { nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)p+pHitEnt->yoffs, // マップ元文字列のアドレス pHitEnt->yoreilen, // マップ元文字列のバイト数 yorei, // マップ先ワイド文字列を入れるバッファのアドレス maxyorei // バッファのサイズ ); yorei[nChar] = 0; } if ( pHitEnt->phoneticlen>0 ) { if ( phoneticUniMap ) { MapPhoneticUni( p+pHitEnt->poffs,pHitEnt->phoneticlen, phonetic, maxphonetic,phoneticUniMap ); } else { nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)p+pHitEnt->poffs, // マップ元文字列のアドレス pHitEnt->phoneticlen, // マップ元文字列のバイト数 phonetic, // マップ先ワイド文字列を入れるバッファのアドレス maxphonetic // バッファのサイズ ); phonetic[nChar] = 0; } } } #else strcpy( title, (LPTSTR)pTitlePool+pHitEnt->titleoffs ); int datasize = min( maxhonbun, pHitEnt->honbunlen ); memcpy( honbun, p+pHitEnt->hoffs, datasize ); honbun[ datasize ] = '\0'; if ( pHitEnt->yoreilen>0 ) { datasize = min( maxyorei, pHitEnt->yoreilen ); memcpy( yorei, p+pHitEnt->yoffs, datasize ); yorei[ datasize ] = '\0'; } if ( pHitEnt->phoneticlen>0 ) { datasize = min( maxphonetic, pHitEnt->phoneticlen ); memcpy( phonetic, p+pHitEnt->poffs, datasize ); phonetic[ datasize ] = '\0'; } #endif *level = pHitEnt->level; return 0; } // 順次検索で先頭に位置づける // 0 正常 // -1 失敗 int CPDicReader::FindFirst() { return SeekIndex( 0 ); } // 指定したインデックス番号の示すデータブロックに位置づける // 0 正常 // -1 失敗 int CPDicReader::SeekIndex( unsigned long idxno ) { byte _titlestr[PDIC_MAX_TITLE+1]; // インデックスに記録された見出し語 int _titlelen; m_seq_idxno = idxno; m_seq_datablk = 0; if ( m_pIndex->ReadRec( m_seq_idxno, &m_seq_datablk, (byte*)_titlestr,&_titlelen ) != 0 ) { return -1; } if ( m_pData->ReadBlks( m_seq_datablk ) != 0 ) { return -1; } return 0; } #if defined(UNICODE) int CPDicReader::MapPhoneticUni( LPCTSTR src,int slen, LPTSTR dest, int maxdest, unsigned short (*CMap)[256][2] ) { int i,dlen; dlen = 0; for ( i=0; i= ' ' && src[i]<256 && (*CMap)[src[i]][0] ) { *dest++ = (*CMap)[src[i]][0]; ++dlen; if ( (*CMap)[src[i]][1] ) { *dest++ = (*CMap)[src[i]][1]; ++dlen; } } else { *dest++ = src[i]; ++dlen; } if ( dlen>=maxdest-1 ) break; } *dest = '\0'; return dlen; } int CPDicReader::MapPhoneticUni( byte* src,int slen, LPTSTR dest, int maxdest, unsigned short (*CMap)[256][2] ) { int i,dlen; dlen = 0; for ( i=0; i= ' ' && src[i]<256 && (*CMap)[src[i]][0] ) { *dest++ = (*CMap)[src[i]][0]; ++dlen; if ( (*CMap)[src[i]][1] ) { *dest++ = (*CMap)[src[i]][1]; ++dlen; } } else { *dest++ = src[i]; ++dlen; } if ( dlen>=maxdest-1 ) break; } *dest = '\0'; return dlen; } #endif // 順次検索で次のレコードを読む // 0 正常 // -1 これ以上のレコードはない int CPDicReader::ReadNext( LPTSTR title, // 見出し語(unicodeの場合、UCS-2) int maxtitle, // 見出し語の領域の最大長(max:1024) LPTSTR honbun, // 訳語(unicodeの場合、UCS-2) int maxhonbun, // 訳語の領域の最大長(max:3000) LPTSTR yorei, // 用例(unicodeの場合、UCS-2) int maxyorei, // 用例の領域の最大長(max:20000) LPTSTR phonetic, // 発音(unicodeの場合、UCS-2) int maxphonetic, // 発音の領域の最大長(max:1000) int*level, // 単語レベル unsigned short (*phoneticUniMap)[256][2] , PDIC_ITEMINFO *pInfo ) { ASSERT( title ); ASSERT( honbun ); ASSERT( yorei ); ASSERT( phonetic ); title[0] = '\0'; honbun[0] = '\0'; yorei[0] = '\0'; phonetic[0] = '\0'; *level = 0; byte _titlestr[PDIC_MAX_TITLE+1]; // インデックスに記録された見出し語 int _titlelen,_hoffs,_honbunlen,_yoffs,_yoreilen,_poffs,_phoneticlen,_level; // 次のレコードを読む if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level, pInfo )!= 0 ) { // データブロック内の最後のレコードの場合、次のデータブロックを読む // インデックスから、次のデータブロックを得る ++m_seq_idxno; if ( m_pIndex->ReadRec( m_seq_idxno, &m_seq_datablk, (byte*)_titlestr,&_titlelen ) != 0 ) { return -1; } // 次のデータブロックを読む if ( m_pData->ReadBlks( m_seq_datablk ) != 0 ) { return -1; } // 次のレコードを読む if ( m_pData->ReadRec( (byte*)_titlestr, &_titlelen, &_hoffs, &_honbunlen, &_yoffs, &_yoreilen, &_poffs, &_phoneticlen, &_level, pInfo )!= 0 ) { return -1; } } if ( pInfo ) { pInfo->indexno = m_seq_idxno; } byte* p = m_pData->GetBuffer(); byte *_honbun = p+_hoffs; byte *_yorei = p+_yoffs; byte *_phonetic = p+_poffs; #if defined(UNICODE) // Unicode辞書の場合、BOCU1->UCS2 if ( m_header.dictype & 0x08 ) { // BOCU1 if ( _titlelen>0 ) { BOCU1_decode( _titlestr,_titlelen, title, maxtitle ); } if ( _honbunlen>0 ) { BOCU1_decode( _honbun,_honbunlen, honbun, maxhonbun ); } if ( _yoreilen>0 ) { BOCU1_decode( _yorei,_yoreilen, yorei, maxyorei ); } if ( _phoneticlen>0 ) { if ( phoneticUniMap /*&& m_pdic_ver < 6*/ ) { TCHAR tmp_phonetic[PDIC_MAX_PHONETIC+1]; BOCU1_decode( _phonetic,_phoneticlen, tmp_phonetic, maxphonetic ); MapPhoneticUni( tmp_phonetic,_tcslen(tmp_phonetic), phonetic, maxphonetic, phoneticUniMap ); } else { BOCU1_decode( _phonetic,_phoneticlen, phonetic, maxphonetic ); } } } else { // 非Unicode辞書の場合、ShiftJIS->UCS2 int nChar; if ( _titlelen>0 ) { nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)_titlestr, // マップ元文字列のアドレス _titlelen, // マップ元文字列のバイト数 title, // マップ先ワイド文字列を入れるバッファのアドレス maxtitle // バッファのサイズ ); title[nChar] = 0; } if ( _honbunlen>0 ) { nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)_honbun, // マップ元文字列のアドレス _honbunlen, // マップ元文字列のバイト数 honbun, // マップ先ワイド文字列を入れるバッファのアドレス maxhonbun // バッファのサイズ ); honbun[nChar] = 0; } if ( _yoreilen>0 ) { nChar = ::MultiByteToWideChar( _KANJI_CP, // コードページ 0, // 文字の種類を指定するフラグ (char*)_yorei, // マップ元文字列のアドレス _yoreilen, // マップ元文字列のバイト数 yorei, // マップ先ワイド文字列を入れるバッファのアドレス maxyorei // バッファのサイズ ); yorei[nChar] = 0; } if ( _phoneticlen>0 ) { if ( phoneticUniMap ) { MapPhoneticUni( _phonetic,_phoneticlen, phonetic, maxphonetic, phoneticUniMap ); } else { int ix; for ( ix=0;ix<_phoneticlen;++ix ) { phonetic[ix] = _phonetic[ix]; } phonetic[_phoneticlen] = 0; } } } #else if ( _titlelen>0 ) { ASSERT(_titlelen<=maxtitle); memcpy( title, _titlestr, _titlelen ); title[_titlelen] = '\0'; } if ( _honbunlen>0 ) { ASSERT(_honbunlen<=maxhonbun); memcpy( honbun, _honbun, _honbunlen ); honbun[_honbunlen] = '\0'; } if ( _yoreilen>0 ) { ASSERT(_yoreilen<=maxyorei); memcpy( yorei, _yorei, _yoreilen ); yorei[_yoreilen] = '\0'; } if ( _phoneticlen>0 ) { ASSERT(_phoneticlen<=maxphonetic); memcpy( phonetic, _phonetic, _phoneticlen ); phonetic[_phoneticlen] = '\0'; } #endif *level = _level; return 0; } // PDICの辞書情報をテキストで表示 void CPDicReader::PDicDumpInfo( char*pBuf,int maxbuf, int bCRLF) { NEWDIC3_5 *pHeader = GetHeader(); if ( !pHeader ) return; int slen = 0; sprintf( pBuf+slen,"[Personal Dictionary]\r\n"); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 辞書名(dictitle) // sprintf( pBuf+slen,"dictitle = %s\r\n", pHeader->dictitle ); // slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 辞書のバージョン(version) sprintf( pBuf+slen,"version = %d.%02d\r\n", pHeader->version>>8, pHeader->version & 0xff ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 見出語の最大長(lword) sprintf( pBuf+slen,"lword = %d\r\n", pHeader->lword ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 訳語の最大長(ljapa) sprintf( pBuf+slen,"ljapa = %d\r\n", pHeader->ljapa ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // ブロックのバイト数(block_size) sprintf( pBuf+slen,"block_size = %d\r\n", pHeader->block_size ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // インデックスブロック数(index_block) sprintf( pBuf+slen,"index_block = %d\r\n", pHeader->index_block ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // ヘッダ長(header_size) sprintf( pBuf+slen,"header_size = %d\r\n", pHeader->header_size ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 登録単語数(nword) sprintf( pBuf+slen,"nword = %d\r\n", pHeader->nword ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 辞書の順番(dicorder) sprintf( pBuf+slen,"dicorder= [%02x] %s\r\n", pHeader->dicorder, (pHeader->dicorder == 0x00 )?"code order ": (pHeader->dicorder == 0x01 )?"ignore case ": (pHeader->dicorder == 0x02 )?"lexicographic order ": (pHeader->dicorder == 0x03 )?"descending order ": "" ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 辞書の種別(dictype) sprintf( pBuf+slen,"dictype = [%02x] %s\r\n", pHeader->dictype, (pHeader->dictype == 0x01)?"AR compressed": (pHeader->dictype == 0x08)?"BOCU-1 compressed": (pHeader->dictype == 0x09)?"AR compressed / BOCU-1 compressed": "" ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 単語属性の長さ(attrlen) sprintf( pBuf+slen,"attrlen = %d\r\n", pHeader->attrlen ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // os type sprintf( pBuf+slen,"os = [%02x] %s\r\n", pHeader->os, (pHeader->os==0x00)?"DOS,Windows,OS/2": (pHeader->os==0x01)?"Mac": (pHeader->os==0x02)?"UNIX - SJIS": (pHeader->os==0x03)?"UNIX - EUC": (pHeader->os==0x04)?"UNIX - JIS": (pHeader->os==0x20)?"BOCU encoding": "" ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // index_blkbit; // 0:16bit, 1:32bit sprintf( pBuf+slen,"index_blkbit = [%02x] %s\r\n", pHeader->index_blkbit, (pHeader->index_blkbit==0x00)?"16bit": (pHeader->index_blkbit==0x01)?"32bit": "" ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // インデックス要素の数(nindex2) sprintf( pBuf+slen,"nindex2 = %d\r\n", pHeader->nindex2 ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; // 使用データブロック数 sprintf( pBuf+slen,"nblock2 = %d\r\n", pHeader->nblock2 ); slen += strlen(pBuf+slen); if ( slen>=maxbuf-255 ) return; } ////////////////////////////////////////////////////////////////////// // インデックス部 ////////////////////////////////////////////////////////////////////// CPDicIndex::CPDicIndex( FILE*fp, NEWDIC3_5 *header ) { ASSERT( fp ); ASSERT( header ); m_fp = fp; m_header = header; m_pdic_ver = (m_header->version) >> 8; m_indexTbl = NULL; m_maxIndex = 0; } CPDicIndex::~CPDicIndex() { if ( m_indexTbl ) { free( m_indexTbl ); m_indexTbl = NULL; } } #ifdef _WIN32_WCE // バッファ付read(WindowsCEのReadFile()がバッファリングされず効率が悪いため) int buffered_read( byte*_iobuf, // I/Oバッファ unsigned int bufsize, // I/Oバッファのサイズ byte**_bufp, // I/Oバッファのポインタ(初期値は、_iobuf+bufsizeとすること) int size, // 入力データのサイズ byte*outbuf, // 入力データを格納する領域 FILE*m_fp // file pointer ) { int _written = 0; while ( _written < size ) { if ( (*_bufp) < _iobuf+bufsize ) { *outbuf++ = **_bufp; (*_bufp)++; ++_written; } else { if ( fread( _iobuf, 1, bufsize, m_fp ) != bufsize ) return _written; *_bufp = _iobuf; *outbuf++ = **_bufp; (*_bufp)++; ++_written; } } return _written; } #endif // インデックス部を読み取り、配列に格納 // 0 正常 // -1 失敗 int CPDicIndex::LoadIndex() { unsigned long _curIdxNo; unsigned long _curoffs = 0; // インデックス先頭からのオフセット m_maxIndex = m_header->nindex2; m_indexTbl = (PDIC_INDEX*)malloc( (m_maxIndex+1)*sizeof(PDIC_INDEX) ); memset( m_indexTbl, 0, (m_maxIndex+1)*sizeof(PDIC_INDEX) ); // if ( fseek( m_fp, PDIC_HEADER_256, SEEK_SET ) ) { if ( fseek( m_fp, m_header->header_size, SEEK_SET ) ) { return -1; } #ifdef _WIN32_WCE byte _iobuf[PDIC_MAX_BLKLEN]; byte *_bufp = _iobuf+m_header->block_size; #endif byte _buffer[4]; unsigned long _blk; for ( _curIdxNo = 0; _curIdxNo=m_maxIndex*m_header->block_size ) break; _blk = 0; if ( m_header->index_blkbit == 1 ) { #ifdef _WIN32_WCE if ( buffered_read( _iobuf,m_header->block_size, &_bufp, 4, _buffer, m_fp )!= 4 ) break; #else if ( fread( _buffer, 1, 4, m_fp ) != 4 ) break; #endif _blk = (_buffer[0]) + (_buffer[1]<<8) + (_buffer[2]<<16) + (_buffer[3]<<24); _curoffs += 4; } else { #ifdef _WIN32_WCE if ( buffered_read( _iobuf,m_header->block_size, &_bufp, 2, _buffer, m_fp )!= 2 ) break; #else if ( fread( _buffer, 1, 2, m_fp ) != 2 ) break; #endif _blk = (_buffer[0]) + (_buffer[1]<<8); _curoffs += 2; } m_indexTbl[_curIdxNo].offs = _curoffs; m_indexTbl[_curIdxNo].blkno = _blk; int _titlelen = 0; #ifdef _WIN32_WCE while ( buffered_read( _iobuf,m_header->block_size, &_bufp, 1, _buffer, m_fp )>0 ) { #else while ( fread( _buffer, 1, 1, m_fp )>0 ) { #endif ++_titlelen; if ( !_buffer[0] ) break; } m_indexTbl[_curIdxNo].titlelen = _titlelen - 1; _curoffs += _titlelen; if ( m_indexTbl[_curIdxNo].blkno == 0 && m_indexTbl[_curIdxNo].titlelen == 0 ) { // 終了条件 break; } } return 0; } // インデックスブロック内での順次エントリread // 0 正常 // -1 これ以上のレコードはない int CPDicIndex::ReadRec( unsigned long idxno, // インデックス番号(0..nindex2) unsigned long *datablk, byte*title, int *titlelen ) { if ( idxno>=(unsigned long)m_header->nindex2 ) return -1; ASSERT( idxno>=0 && (long)idxnonindex2 ); if ( !m_indexTbl ) { LoadIndex(); // インデックスを読み込み } // if ( fseek( m_fp, PDIC_HEADER_256 + m_indexTbl[idxno].offs, SEEK_SET ) ) { if ( fseek( m_fp, m_header->header_size + m_indexTbl[idxno].offs, SEEK_SET ) ) { #if defined(_WIN32_WCE) RaiseException( EXCEPTION_CODE, /*DWORD dwExceptionCode*/ 0, /*DWORD dwExceptionFlags*/ 0, /*DWORD nNumberOfArguments*/ NULL); /*ULONG_PTR *lpArguments*/ #else throw; #endif // return -1; } ASSERT( m_indexTbl[idxno].titlelen<=PDIC_MAX_TITLE ); if ( fread( title, m_indexTbl[idxno].titlelen+1,1, m_fp ) == 0 ) { return -1; } *datablk = m_indexTbl[idxno].blkno; *titlelen = m_indexTbl[idxno].titlelen; return 0; } // インデックス表からバイナリサーチで最も近傍のインデックスを見つける // 「C言語による最新アルゴリズム辞典」奥村晴彦著より int CPDicIndex::BSearchIndex( LPCTSTR keyword ) { unsigned long datablk; int _titlelen; byte _title[PDIC_MAX_TITLE+1]; #if defined(UNICODE) int nChar; TCHAR w_idxkey[PDIC_MAX_TITLE+1]; byte mb_keyword[PDIC_MAX_TITLE+1]; #endif int keywordlen; if ( !m_indexTbl ) { LoadIndex(); // インデックスを読み込み } #if defined(UNICODE) if ( m_header->dictype & 0x08 ) { // BOCU1 keywordlen = _tcslen(keyword); } else { nChar = ::WideCharToMultiByte( _KANJI_CP, NULL, keyword, _tcslen(keyword), (LPSTR)mb_keyword, PDIC_MAX_TITLE, NULL, NULL); // 変換(→ShiftJIS) mb_keyword[nChar] = '\0'; keywordlen = nChar; } #else keywordlen = _tcslen(keyword); #endif int left = 0; // インデックス部のブロック番号 int right = m_header->nindex2; int mid; while ( left < right ) { mid = ( left + right ) / 2; if ( ReadRec( mid, &datablk,_title,&_titlelen ) ) return 0; int comp; //////////////////////////////////////////////////// // 以下はdicorder == 0 (コード順)の場合 //////////////////////////////////////////////////// #if defined(UNICODE) // Unicode辞書の場合、BOCU1->UCS2に変換して比較 if ( m_header->dictype & 0x08 ) { // BOCU1 BOCU1_decode( _title,_titlelen, w_idxkey,PDIC_MAX_TITLE ); comp = _tcsncmp( w_idxkey , keyword, keywordlen ); } else { // 非Unicode辞書の場合、ShiftJISで比較する(文字コード順) // _mbsncmp()はうまく動かない comp = strncmp( (char*)_title, (char*)mb_keyword, keywordlen ) ; } #else // _mbsncmp()はうまく動かない comp = strncmp( (char*)_title , keyword, keywordlen ); #endif if ( comp < 0 ) left = mid + 1; else right = mid; } return max(0,left-1); } ////////////////////////////////////////////////////////////////////// // データ部 ////////////////////////////////////////////////////////////////////// CPDicData::CPDicData(FILE*fp,NEWDIC3_5 *header) { ASSERT( fp ); ASSERT( header ); m_fp = fp; m_header = header; m_pdic_ver = (m_header->version) >> 8; m_curBlk = 0xFFFFFFFF; m_recOffs = 0; m_blocks = 0; // 使用ブロック数 m_maxblocks = 0; m_blkbuf = NULL; } CPDicData::~CPDicData() { if ( m_blkbuf ) { free( m_blkbuf ); m_blkbuf = NULL; } } // 連続データブロックの先頭アドレスを返す byte*CPDicData::GetBuffer() { return m_blkbuf; } unsigned long CPDicData::GetOffs() { return m_recOffs; } unsigned long CPDicData::GetBlkNo() // 現在の連続ブロック先頭番号 { return m_curBlk; } // blknoから始まる連続データブロックを読む // ただし複数ブロックの連結の機能はNEWDIC3以降 // 0 正常 // -1 失敗 int CPDicData::ReadBlks( unsigned long blkno /*データ部の物理ブロック番号*/ ) { /* 先頭ブロックのMSB 0: フィールド長2バイト 1: フィールド長4バイト 先頭ブロックの先頭2バイトは使用ブロック数;0なら空きブロック ブロック長は256バイト 使用ブロック数>1なら連結ブロック */ if ( m_curBlk == blkno ) { // 読み込み済 m_recOffs = 2; // 使用ブロック数を読み飛ばす return 0; } m_curBlk = blkno; m_recOffs = 0; // 先頭ブロックを読む if ( ReadBlk( blkno ) ) return -1; // フィールド長の決定と使用ブロック数を得る m_blocks = LTWOBYTEUINT(m_buffer); if ( m_blocks & 0x8000 ) { m_fieldSize = 4; } else { m_fieldSize = 2; } m_blocks &= 0x7FFF; // 使用ブロック数0なら空きブロックである if ( m_blocks == 0 ) return -1; // 空きブロックだった // 使用ブロック数が入るだけの領域を動的に割り当てる if ( m_maxblocks == 0 ) { m_blkbuf = (byte*)malloc( m_blocks*m_header->block_size ); m_maxblocks = m_blocks; } else if ( m_maxblocks < m_blocks ) { m_blkbuf = (byte*)realloc( m_blkbuf, m_blocks*m_header->block_size ); m_maxblocks = m_blocks; } memset( m_blkbuf, 0, m_blocks*m_header->block_size ); memcpy( m_blkbuf+0, m_buffer, m_header->block_size ); // 連続するブロックをメモリに読み込む int _blks; for ( _blks = 1;_blksblock_size, m_buffer, m_header->block_size ); } // 先頭レコード位置に設定 m_recOffs = 2; // 使用ブロック数を読み飛ばす return 0; } // 読込済の連続データブロックから、順にレコードを読む // 各引数はNULLにしてもよい。その場合、callerに複写しない // 0 レコードあり // -1 これ以上のレコードはない int CPDicData::ReadRec( byte* title, // 見出しの読出領域(callerに複写する) // ※NULLにすると複写しない int *titlelen, // titleの最大長(文字数) int *hoffs, // 訳語の開始位置オフセット int *honbunlen, // 訳語の長さ(文字数) int *yoffs, // 用例の開始位置オフセット int *yoreilen, // 用例の長さ int *poffs, // 発音の開始位置オフセット int *phoneticlen, // 発音の長さ int *level, // 単語レベル PDIC_ITEMINFO *pInfo ) { /* データ部: 非Unicode辞書 ================================ 名称 サイズ 備考 フィールド長 2 バイト 見出語から訳語の最後までのバイト単位の長さ(フィールド長、圧縮長は含めない) 圧縮長 1 バイト 見出語部の圧縮している長さを示す 見出語 可変長 NULL 終端 圧縮してある 見出語属性 1 バイト 0x80 必ずつける 下位4bit 単語レベル値(0-15) 0x10 拡張構成フラグ 0x20 暗記必須単語フラグ 0x40 修正単語フラグ 訳語 可変長 NULL 終端無し Unicode辞書 ================================ 名称 サイズ 備考 フィールド長 2 バイト 見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。 圧縮長 1 バイト 見出語部の圧縮している長さ(バイト単位)を示す 見出語属性 1 バイト ※出現位置が違う 見出語 可変長NULL 終端 圧縮長を除いた残りの見出語部分 BOCU1 encoding 訳語 可変長NULL 終端無し BOCU1 encoding */ ASSERT( m_recOffs>=2 && m_recOffs< m_blocks*m_header->block_size); ASSERT( m_blkbuf ); int _fieldLen,_complen,_titlelen,_honbunlen; int _ext_attr,_ext_len; int nextoffs; byte _title_attr; PDIC_ITEMINFO info; /* if ( titlelen ) *titlelen = 0; if ( honbunlen ) *honbunlen = 0; if ( yoreilen ) *yoreilen = 0; if ( phoneticlen ) *phoneticlen = 0; if ( hoffs ) *hoffs = 0; if ( yoffs ) *yoffs = 0; if ( poffs ) *poffs = 0; if ( level ) *level = 0; */ memset( &info,0,sizeof(PDIC_ITEMINFO) ); info.blkno = GetBlkNo(); info.recOffs = m_recOffs; // (1)フィールド長 if ( m_fieldSize == 4 ) { _fieldLen = LFOURBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 4; } else { _fieldLen = LTWOBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 2; } if ( _fieldLen == 0 ) { return -1; // 終了 } // (2)圧縮長 _complen = m_blkbuf[m_recOffs]; ++m_recOffs; if ( m_header->dictype & 0x08 ) { // BOCU1 // (3)見出語属性 _title_attr = m_blkbuf[m_recOffs]; ++m_recOffs; // フィールド長は、見出語から訳語の最後までのバイト単位の長さ nextoffs = m_recOffs+_fieldLen; // (4)見出語 NULL終端 _titlelen = strlen( (char*)m_blkbuf+m_recOffs); int _full_titlelen = _complen+_titlelen; ASSERT( _full_titlelen <= PDIC_MAX_TITLE ); strncpy( (char*)m_lastTitle+_complen, (char*)m_blkbuf+m_recOffs,_titlelen ); m_lastTitle[ _full_titlelen ] = 0; if ( title ) { strncpy( (char*)title,(char*)m_lastTitle,_full_titlelen ); title[ _full_titlelen ] = 0; } info.titlelen = _full_titlelen; m_recOffs += _titlelen + 1; // (5)訳語 NULL終端 info.hoffs = m_recOffs; if ( _title_attr & 0x10 ) { // 拡張属性 _honbunlen = strlen( (char*)m_blkbuf+m_recOffs); info.hoffs = m_recOffs; info.honbunlen = _honbunlen; m_recOffs += _honbunlen + 1; // この後ろに、拡張属性が続く while( m_recOffs<=nextoffs ) { // 拡張属性 _ext_attr = m_blkbuf[m_recOffs]; ++m_recOffs; if ( _ext_attr == 0x80 ) { break; } else if ( _ext_attr & 0x10 ) { // binary if ( m_fieldSize == 4 ) { _ext_len = LFOURBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 4; } else { _ext_len = LTWOBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 2; } // 読み飛ばす m_recOffs += _ext_len; } else { _ext_len = strlen( (char*)m_blkbuf+m_recOffs); if ( _ext_attr == 0x01 ) { // 用例 info.yoffs = m_recOffs; info.yoreilen = _ext_len; } else if ( _ext_attr == 0x02 ) { // 発音記号 info.poffs = m_recOffs; info.phoneticlen = _ext_len; } m_recOffs += _ext_len+1; } } ASSERT( m_recOffs == nextoffs ); m_recOffs = nextoffs; } else { // 拡張属性無 _honbunlen = nextoffs - m_recOffs; info.hoffs = m_recOffs; info.honbunlen = _honbunlen; m_recOffs = nextoffs; } info.level = _title_attr & 0x0f; } else { // (3)見出語 NULL終端 _titlelen = strlen( (char*)m_blkbuf+m_recOffs); int _full_titlelen = _complen+_titlelen; ASSERT( _full_titlelen <= PDIC_MAX_TITLE ); strncpy( (char*)m_lastTitle+_complen, (char*)m_blkbuf+m_recOffs,_titlelen ); m_lastTitle[ _full_titlelen ] = 0; if ( title ) { strncpy( (char*)title,(char*)m_lastTitle,_full_titlelen ); title[ _full_titlelen ] = 0; } info.titlelen = _full_titlelen; m_recOffs += _titlelen + 1; // (4)見出語属性 _title_attr = m_blkbuf[m_recOffs]; ++m_recOffs; // (5)訳語 拡張属性の場合はNULL終端 if ( _title_attr & 0x10 ) { // 拡張属性 _honbunlen = strlen( (char*)m_blkbuf+m_recOffs); info.hoffs = m_recOffs; info.honbunlen = _honbunlen; nextoffs = m_recOffs + _fieldLen - _titlelen - 2; m_recOffs += _honbunlen + 1; // この後ろに、拡張属性が続く while( m_recOffs<=nextoffs ) { // 拡張属性 _ext_attr = m_blkbuf[m_recOffs]; ++m_recOffs; if ( _ext_attr == 0x80 ) { break; } else if ( _ext_attr & 0x10 ) { // binary if ( m_fieldSize == 4 ) { _ext_len = LFOURBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 4; } else { _ext_len = LTWOBYTEUINT(m_blkbuf+m_recOffs); m_recOffs += 2; } // 読み飛ばす m_recOffs += _ext_len; } else { _ext_len = strlen( (char*)m_blkbuf+m_recOffs); if ( _ext_attr == 0x01 ) { // 用例 info.yoffs = m_recOffs; info.yoreilen = _ext_len; } else if ( _ext_attr == 0x02 ) { // 発音記号 info.poffs = m_recOffs; info.phoneticlen = _ext_len; } m_recOffs += _ext_len+1; } } ASSERT( m_recOffs == nextoffs ); m_recOffs = nextoffs; } else { // 拡張属性無 _honbunlen = _fieldLen - _titlelen - 2; info.hoffs = m_recOffs; info.honbunlen = _honbunlen; m_recOffs += _honbunlen; } info.level = _title_attr & 0x0f; } if ( titlelen ) *titlelen = info.titlelen; if ( hoffs ) *hoffs = info.hoffs; if ( honbunlen ) *honbunlen = info.honbunlen; if ( yoffs ) *yoffs = info.yoffs; if ( yoreilen ) *yoreilen = info.yoreilen; if ( poffs ) *poffs = info.poffs; if ( phoneticlen ) *phoneticlen = info.phoneticlen; if ( level ) *level = info.level; if ( pInfo ) { info.blocks = m_blocks; info.fieldSize = m_fieldSize; *pInfo = info; } return 0; } // 下位I/F 物理データブロックを読む // 0 正常 // -1 失敗 int CPDicData::ReadBlk( unsigned long blkno ) { unsigned long seekoffs; // Seek if ( (m_header->version>>8) >= 4 ) { seekoffs = m_header->header_size + m_header->extheader + m_header->index_block * m_header->block_size + m_header->block_size * blkno; } else { seekoffs = m_header->header_size + m_header->index_size + m_header->block_size * blkno; } if ( fseek( m_fp, seekoffs, SEEK_SET ) ) { // return -1; #if defined(_WIN32_WCE) RaiseException( EXCEPTION_CODE, /*DWORD dwExceptionCode*/ 0, /*DWORD dwExceptionFlags*/ 0, /*DWORD nNumberOfArguments*/ NULL); /*ULONG_PTR *lpArguments*/ #else throw; #endif } // データブロックを読む if ( fread( m_buffer, 1, m_header->block_size, m_fp ) != (unsigned int)m_header->block_size ) { return -1; } return 0; }