From: Olyutorskii Date: Mon, 23 May 2011 16:02:52 +0000 (+0900) Subject: 文字デコーディング処理の分離 X-Git-Tag: fromMercurial~72 X-Git-Url: http://git.osdn.net/view?p=mikutoga%2FTogaGem.git;a=commitdiff_plain;h=e28e393729f4614807c5bab69df8e7a7be6e94b1 文字デコーディング処理の分離 --- diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/TextDecoder.java b/src/main/java/jp/sourceforge/mikutoga/parser/TextDecoder.java new file mode 100644 index 0000000..08f3821 --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/parser/TextDecoder.java @@ -0,0 +1,118 @@ +/* + * character decoder + * + * License : The MIT License + * Copyright(c) 2011 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.parser; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +/** + * 文字デコーダー。 + */ +public class TextDecoder { + + /** デコード作業用入力バッファ長のデフォルト。バイト単位。 */ + public static final int BYTEBUF_SZ = 512; + + /** バッファ成長率。 */ + private static final double WIDEN_RATE = 1.5; + + + private final CharsetDecoder decoder; + + private byte[] byteArray; + private ByteBuffer byteBuffer; // byteArrayの別ビュー + private CharBuffer charBuffer; + private CharBuffer roBuffer; // charBufferの閲覧用ビュー + + + /** + * コンストラクタ。 + * @param cs キャラクタセット + */ + public TextDecoder(Charset cs){ + this(cs.newDecoder()); + return; + } + + /** + * コンストラクタ。 + * @param decoder デコーダ + */ + protected TextDecoder(CharsetDecoder decoder){ + super(); + this.decoder = decoder; + this.decoder.onMalformedInput(CodingErrorAction.REPORT); + this.decoder.onUnmappableCharacter(CodingErrorAction.REPORT); + return; + } + + /** + * 指定されたサイズで文字デコード用バッファを用意する。 + * 既存バッファで足りなければ新たに確保し直す。 + * @param newSize バッファ長さ。単位はバイト数。 + */ + protected void prepareBuffer(int newSize){ + if(this.byteArray != null && this.byteArray.length >= newSize){ + return; + } + + int rounded = (int)( newSize * WIDEN_RATE ); + + this.byteArray = new byte[rounded]; + this.byteBuffer = ByteBuffer.wrap(this.byteArray); + + float maxCharsPerByte = this.decoder.maxCharsPerByte(); + int maxChars = + (int)( this.byteBuffer.capacity() * maxCharsPerByte ) + 1; + this.charBuffer = CharBuffer.allocate(maxChars); + + this.roBuffer = this.charBuffer.asReadOnlyBuffer(); + + return; + } + + /** + * バイト列を読み込み文字列へデコーディングする。 + * @param source 入力ソース + * @param byteSize 読み込みバイトサイズ + * @return 文字へのデコード結果。 + * @throws MmdEofException 意図しないファイル末端 + * @throws MmdFormatException 矛盾したバイトシーケンス + * もしくは未定義文字 + * @throws IOException 入力エラー + */ + public CharBuffer parseString(MmdSource source, int byteSize) + throws MmdEofException, MmdFormatException, IOException{ + prepareBuffer(byteSize); + + source.parseByteArray(this.byteArray, 0, byteSize); + this.byteBuffer.rewind().limit(byteSize); + + this.charBuffer.clear(); + + this.decoder.reset(); + CoderResult decResult = + this.decoder.decode(this.byteBuffer, this.charBuffer, true); + if(decResult.isError()){ + throw new MmdFormatException("illegal character encoding", + source.getPosition() ); + }else if(decResult.isOverflow()){ + assert false; + } + + this.roBuffer.rewind().limit(this.charBuffer.position()); + + return this.roBuffer; + } + +}