付録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 {
// 解放すべきリソースがないため,何もしない
}
}