付録H.4 CSCOwnCodeReaderインターフェース
文字コード変換UOCを開発する場合,CSCOwnCodeReaderインターフェースの実装クラスを作成します。未定義文字をセパレータに使用する場合はこのインターフェースを実装してください。
(1) インターフェース
CSCOwnCodeReaderインターフェースを次に示します。
- インターフェース名
-
CSCOwnCodeReaderインターフェース
- 説明
-
独自文字コードの文字列を読み込むためのインターフェースです。
CSCOwnCodeReaderのパッケージ名は,jp.co.Hitachi.soft.csc.dt.uoc.CSCOwnCodeReaderです。
バイナリ文字列の読み込み処理で,文字コードを変換しないでセパレータを解析することで,バイト数や文字数が変化する変換の制限を緩和したり,変換の性能を向上させたりします。
このインターフェースの実装は任意です。実装していない場合,文字コード変換を実行してセパレータを解析します。
このインターフェースのインスタンスは,複数のスレッドで共用されるため,実装はスレッドセーフにする必要があります。
- 形式
package jp.co.Hitachi.soft.csc.dt.uoc ; import jp.co.Hitachi.soft.csc.dt.uoc.CSCOwnCodeConverterException ; public interface CSCOwnCodeReader { CSCOwnCodeReaderContext start( byte[] data, int offset, int length ) throws CSCOwnCodeConverterException ; boolean readChar( CSCOwnCodeReaderContext context ) throws CSCOwnCodeConverterException ; void end( CSCOwnCodeReaderContext context ) ; }
- メソッド
-
CSCOwnCodeReaderインターフェースのメソッドを次の表に示します。
メソッド名
説明
startメソッド
独自文字コード文字列の読み込みを開始するためのメソッドです。
readCharメソッド
独自文字コード文字を1文字読み込むメソッドです。
endメソッド
独自文字コード文字列の読み込みを終了するメソッドです。
データ変換の対象が可変長文字列で,かつバイナリフォーマット定義にセパレータが設定されている場合,データ変換はセパレータの解析処理を実行します。CSCOwnCodeReaderおよびCSCOwnCodeReaderContextの各メソッドの呼び出し順序を次の図に示します。
-
インスタンス生成
データ変換によってCSCOwnCodeReaderのインスタンスを生成します。
-
CSCOwnCodeReader#startメソッド
自スレッド専用のCSCOwnCodeReaderContextのインスタンスを生成します。以降,CSCOwnCodeReaderとの値の受け渡しは,自スレッドが保持するCSCOwnCodeReaderContextのインスタンスで実行します。
-
CSCOwnCodeReader#readCharメソッド
readCharの実行時,データ変換の処理は引数にCSCOwnCodeReaderContextのインスタンスを渡します。readCharの処理では,解析結果をCSCOwnCodeReaderContextのインスタンスにセットします。セットされた解析結果は,データ変換の処理でセパレータの解析に使用します。
-
getPositionメソッド,getLengthメソッド,canSeparateメソッド
それぞれのメソッドは,データ変換から呼ばれます。メソッドの実行順序は電文フォーマットに依存します。
-
getPositionメソッド
このメソッドで現在の文字位置を返します。
-
getLengthメソッド
このメソッドで現在の文字長を返します。
-
canSeparateメソッド
このメソッドで現在の文字をセパレータの解析対象とするかどうかを返します。
-
-
CSCOwnCodeReader#endメソッド
CSCOwnCodeReaderContextの実装クラスの解放処理が必要な場合は,endメソッドを実行します。
(a) startメソッド
- 説明
-
独自文字コード文字列の読み込みを開始します。
- 形式
public CSCOwnCodeReaderContext start( byte[] data, int offset, int length )
- パラメタ
-
- data:
-
読み込み対象データです。
- offset:
-
読み込み開始位置です。
- length:
-
読み込み開始位置からの長さです。
- 例外
-
- CSCOwnCodeConverterException:
-
文字コード変換処理中に異常が発生したため,データ変換処理全体を中断しました。
- 戻り値
-
CSCOwnCodeReaderContextの実装クラスのインスタンスです。このインスタンスは,ほかのスレッドで使用できません。
(b) readCharメソッド
- 説明
-
独自文字コード文字を1文字読み込みます。
文字の位置,長さは,CSCOwnCodeReaderContext#getPosition,CSCOwnCodeReaderContext#getLengthで取得できます。
- 形式
public boolean readChar( CSCOwnCodeReaderContext context )
- パラメタ
-
- context:
-
#startで返されたCSCOwnCodeReaderContextの実装クラスのインスタンスです。
- 例外
-
- CSCOwnCodeConverterException:
-
文字コード変換処理中に異常が発生したため,データ変換処理全体を中断しました。
- 戻り値
-
読み込める上限を超えた場合,および文字を変換できない場合,falseを返します。それ以外の場合はtrueを返します。
(c) endメソッド
- 説明
-
独自文字コード文字列の読み込みを終了します。
読み込み処理の成功または失敗(エラー)に関係なく必ず呼ばれます。
- 形式
public void end( CSCOwnCodeReaderContext context )
- パラメタ
-
- context:
-
#startで返されたCSCOwnCodeReaderContextの実装クラスのインスタンスです。
- 例外
-
- CSCOwnCodeConverterException:
-
文字コード変換処理中に異常が発生したため,データ変換処理全体を中断しました。
- 戻り値
-
なし。
(2) 例外クラス
文字コード変換UOCの開発時に発生する例外クラスを次に示します。
- クラス名
-
CSCOwnCodeConverterExceptionクラス
- 説明
-
文字コード変換処理中に異常が発生した場合に送出する例外です。
この例外が発生した場合は,データ変換処理全体を中断します。
(3) 実装例(MS932)
CSCOwnCodeReaderインターフェースの実装例(MS932)を次に示します。
public class CSCOwnCodeReaderImpl implements CSCOwnCodeConverter, CSCOwnCodeReader { private static final String UNICODE = "ISO-10646-UCS-2" ; private final HJCOption option ; private static byte[] charSizeTable = initCharSizeTable() ; private static byte[] initCharSizeTable() { final byte[] objTable = new byte[0x100] ; for ( int i = 0; i <= 0xff; i++ ) { if ( i <= 0x80 || (i >= 0xA0 && i <= 0xDF) || (i >= 0xFD && i <= 0xFF) ) { objTable[i] = 1 ; } else { objTable[i] = 2 ; } } return objTable ; } public CSCOwnCodeReaderImpl() { option = new HJCOption() ; try { // Unicodeはビッグエンディアン option.enableOption( HJCOption.COP_BIGENDIAN ) ; } catch ( Exception e ) { e.printStackTrace() ; } } @Override public void setProperties( Properties properties ) throws CSCOwnCodeConverterException { String codetablepath = null ; if ( properties != null ) { codetablepath = properties.getProperty( "codetablepath" ) ; } try { if ( codetablepath == null ) { option .setTablePath( "C:\\Program Files\\HITACHI\\Cosminexus\\CSC\\lib\\external\\table" ) ; } else { option.setTablePath( codetablepath ) ; } } catch ( Exception e ) { e.printStackTrace() ; } } @Override public int available( byte[] inBuffer ) throws CSCOwnCodeConverterException { if ( inBuffer == null ) { final String message = "空文字列は変換できません。" ; throw new CSCOwnCodeConverterException( message ) ; } int retInt = -1 ; final HJCResult result = new HJCResult() ; final HJCString inStr = new HJCString( inBuffer ) ; try { HJCConverters.cs_ms932tounicode( inStr, result, option ) ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } final byte[] resultData = result.getStrResult().getBytes() ; final int resultState = result.getConvertState() ; if ( resultState == HJCConvertState.CST_NORMAL ) { // 変換が正常終了 if ( resultData != null ) { retInt = result.getResultLength() ; } } else { // 変換が異常終了 final byte[] bytes = new byte[result.getResultLength() - 1] ; System.arraycopy( inBuffer, 0, bytes, 0, result.getResultLength() - 1 ) ; retInt = available( bytes ) ; } return retInt ; } @Override public char[] ownCodeToUnicode( byte[] inBuffer ) throws CSCOwnCodeConverterException { char[] retChar = null ; final HJCResult result = new HJCResult() ; final HJCString inStr = new HJCString( inBuffer ) ; try { HJCConverters.cs_ms932tounicode( inStr, result, option ) ; final byte[] resultData = result.getStrResult().getBytes() ; final String retstr = new String( resultData, UNICODE ) ; retChar = retstr.toCharArray() ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } return retChar ; } @Override public byte[] unicodeToOwnCode( char[] inBuffer ) throws CSCOwnCodeConverterException { byte[] retByte = null ; final String data = new String( inBuffer ) ; final HJCResult result = new HJCResult() ; try { final HJCString inStr = new HJCString( data.getBytes( UNICODE ) ) ; HJCConverters.cs_unicodetoms932( inStr, result, option ) ; retByte = result.getStrResult().getBytes() ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } return retByte ; } @Override public CSCOwnCodeReaderContext start( byte[] data, int offset, int length ) throws CSCOwnCodeConverterException { return new CSCOwnCodeReaderContextImpl( Arrays.copyOfRange( data, offset, length ) ) ; } @Override public boolean readChar( CSCOwnCodeReaderContext context ) throws CSCOwnCodeConverterException { final CSCOwnCodeReaderContextImpl contextImpl = (CSCOwnCodeReaderContextImpl)context ; final int offset = contextImpl.getNextPosition() ; contextImpl.setPosition( offset ) ; final byte[] data = contextImpl.getData() ; // 入力データの最大長を取得(文字のサイズではない) final int maxLength = data.length ; if ( offset >= maxLength ) { // 現在位置が入力データの範囲外である return false ; } final int len = charSizeTable[data[offset] & 0xff] ; contextImpl.setLength( len ) ; final int next = offset + len ; contextImpl.setNextPosition( next ) ; if ( next > maxLength ) { // 変換結果が異常 // 入力データが不正な場合に発生 // falseを返して解析を中止する return false ; } return true ; } @Override public void end( CSCOwnCodeReaderContext context ) throws CSCOwnCodeConverterException { // 解放すべきリソースがないため,何もしない } }
(4) 実装例(IBM漢字コード)
CSCOwnCodeReaderインターフェースの実装例(IBM漢字コード)を次に示します。
public class CSCOwnCodeReaderImpl implements CSCOwnCodeConverter, CSCOwnCodeReader { private static final String UNICODE = "ISO-10646-UCS-2" ; private static final byte SHIFT_SINGLEBYTE = (byte)0x0f ; private static final byte SHIFT_MULTIBYTE = (byte)0x0e ; private final HJCOption option ; public CSCOwnCodeReaderImpl() { option = new HJCOption() ; try { // Unicodeはビッグエンディアン option.enableOption( HJCOption.COP_BIGENDIAN ) ; // EBCDIC option.enableOption( HJCOption.COP_EBCDIC ) ; } catch ( Exception e ) { e.printStackTrace() ; } } @Override public void setProperties( Properties properties ) throws CSCOwnCodeConverterException { String codetablepath = null ; if ( properties != null ) { codetablepath = properties.getProperty( "codetablepath" ) ; } try { if ( codetablepath == null ) { option .setTablePath( "C:\\Program Files\\HITACHI\\Cosminexus\\CSC\\lib\\external\\table" ) ; } else { option.setTablePath( codetablepath ) ; } } catch ( Exception e ) { e.printStackTrace() ; } } @Override public int available( byte[] inBuffer ) throws CSCOwnCodeConverterException { if ( inBuffer == null ) { final String message = "空文字列は変換できません。" ; throw new CSCOwnCodeConverterException( message ) ; } int retInt = -1 ; final HJCResult result = new HJCResult() ; final HJCString inStr = new HJCString( inBuffer ) ; try { HJCConverters.cs_ibmtounicode( inStr, result, option ) ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } final byte[] resultData = result.getStrResult().getBytes() ; final int resultState = result.getConvertState() ; if ( resultState == HJCConvertState.CST_NORMAL ) { // 変換が正常終了 if ( resultData != null ) { retInt = result.getResultLength() ; } } else { // 変換が異常終了 final byte[] bytes = new byte[result.getResultLength() - 1] ; System.arraycopy( inBuffer, 0, bytes, 0, result.getResultLength() - 1 ) ; retInt = available( bytes ) ; } return retInt ; } @Override public char[] ownCodeToUnicode( byte[] inBuffer ) throws CSCOwnCodeConverterException { char[] retChar = null ; final HJCResult result = new HJCResult() ; final HJCString inStr = new HJCString( inBuffer ) ; try { HJCConverters.cs_ibmtounicode( inStr, result, option ) ; final byte[] resultData = result.getStrResult().getBytes() ; final String retstr = new String( resultData, UNICODE ) ; retChar = retstr.toCharArray() ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } return retChar ; } @Override public byte[] unicodeToOwnCode( char[] inBuffer ) throws CSCOwnCodeConverterException { byte[] retByte = null ; final String data = new String( inBuffer ) ; final HJCResult result = new HJCResult() ; try { final HJCString inStr = new HJCString( data.getBytes( UNICODE ) ) ; HJCConverters.cs_unicodetoibm( inStr, result, option ) ; retByte = result.getStrResult().getBytes() ; } catch ( Exception e ) { e.printStackTrace() ; throw new CSCOwnCodeConverterException( e ) ; } return retByte ; } @Override public CSCOwnCodeReaderContext start( byte[] data, int offset, int length ) throws CSCOwnCodeConverterException { final byte[] tempData = Arrays.copyOfRange( data, offset, length ) ; // offsetの位置から解析を開始 return new CSCOwnCodeReaderContextImpl( tempData ) ; } @Override public boolean readChar( CSCOwnCodeReaderContext context ) throws CSCOwnCodeConverterException { final CSCOwnCodeReaderContextImpl contextImpl = (CSCOwnCodeReaderContextImpl)context ; // 現在位置 final int position = contextImpl.getNextPosition() ; // 解析対象の文字列のバイト列 final byte[] data = contextImpl.getData() ; // 解析の上限は入力データの最後まで final int maxLength = data.length ; // 現在位置から1バイトずつ解析する for ( int i = position; i < maxLength; i++ ) { // 次の文字を解析 if ( data[i] == SHIFT_SINGLEBYTE ) { // シングルバイトモードに遷移 contextImpl.setLength( 1 ) ; contextImpl.setCanSeparate( true ) ; continue ; } else if ( data[i] == SHIFT_MULTIBYTE ) { // マルチバイトモードに遷移 contextImpl.setLength( 2 ) ; contextImpl.setCanSeparate( false ) ; continue ; } contextImpl.setPosition( i ) ; contextImpl.setNextPosition( i + contextImpl.getLength() ) ; if ( contextImpl.getNextPosition() > maxLength ) { // データが足りない return false ; } // 解析に成功した return true ; } contextImpl.setPosition( maxLength ) ; contextImpl.setNextPosition( maxLength ) ; return false ; } @Override public void end( CSCOwnCodeReaderContext context ) throws CSCOwnCodeConverterException { // 解放すべきリソースがないため,何もしない } }