4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sourceforge.mikutoga.parser;
10 import java.io.IOException;
11 import java.nio.ByteBuffer;
12 import java.nio.CharBuffer;
13 import java.nio.charset.Charset;
14 import java.nio.charset.CharsetDecoder;
15 import java.nio.charset.CoderResult;
16 import java.nio.charset.CodingErrorAction;
21 public class TextDecoder {
23 /** デコード作業用入力バッファ長のデフォルト。バイト単位。 */
24 public static final int BYTEBUF_SZ = 512;
27 private static final double WIDEN_RATE = 1.5;
30 private final CharsetDecoder decoder;
32 private byte[] byteArray;
33 private ByteBuffer byteBuffer; // byteArrayの別ビュー
34 private CharBuffer charBuffer;
35 private CharBuffer roBuffer; // charBufferの閲覧用ビュー
42 public TextDecoder(Charset cs){
43 this(cs.newDecoder());
51 protected TextDecoder(CharsetDecoder decoder){
53 this.decoder = decoder;
54 this.decoder.onMalformedInput(CodingErrorAction.REPORT);
55 this.decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
60 * 指定されたサイズで文字デコード用バッファを用意する。
61 * 既存バッファで足りなければ新たに確保し直す。
62 * @param newSize バッファ長さ。単位はバイト数。
64 protected void prepareBuffer(int newSize){
65 if(this.byteArray != null && this.byteArray.length >= newSize){
69 int rounded = (int)( newSize * WIDEN_RATE );
71 this.byteArray = new byte[rounded];
72 this.byteBuffer = ByteBuffer.wrap(this.byteArray);
74 float maxCharsPerByte = this.decoder.maxCharsPerByte();
76 (int)( this.byteBuffer.capacity() * maxCharsPerByte ) + 1;
77 this.charBuffer = CharBuffer.allocate(maxChars);
79 this.roBuffer = this.charBuffer.asReadOnlyBuffer();
85 * バイト列を読み込み文字列へデコーディングする。
87 * @param byteSize 読み込みバイトサイズ
89 * @throws MmdEofException 意図しないファイル末端
90 * @throws MmdFormatException 矛盾したバイトシーケンス
92 * @throws IOException 入力エラー
94 public CharBuffer parseString(MmdSource source, int byteSize)
95 throws MmdEofException, MmdFormatException, IOException{
96 prepareBuffer(byteSize);
98 source.parseByteArray(this.byteArray, 0, byteSize);
99 this.byteBuffer.rewind().limit(byteSize);
101 this.charBuffer.clear();
103 this.decoder.reset();
104 CoderResult decResult =
105 this.decoder.decode(this.byteBuffer, this.charBuffer, true);
106 if(decResult.isError()){
107 throw new MmdFormatException("illegal character encoding",
108 source.getPosition() );
109 }else if(decResult.isOverflow()){
113 this.roBuffer.rewind().limit(this.charBuffer.position());
115 return this.roBuffer;