4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sourceforge.mikutoga.binio;
10 import java.io.ByteArrayOutputStream;
11 import java.io.IOException;
12 import java.io.OutputStream;
13 import java.nio.ByteBuffer;
14 import java.nio.CharBuffer;
15 import java.nio.charset.CharacterCodingException;
16 import java.nio.charset.Charset;
17 import java.nio.charset.CharsetEncoder;
18 import java.nio.charset.CoderResult;
19 import java.nio.charset.CodingErrorAction;
22 * 任意のエンコーダによるテキストデータのバイナリ出力を行う。
24 public class TextExporter {
26 /** デフォルトの入力バッファサイズ(単位:char)。 */
27 public static final int DEFBUFSZ_CHAR = 128;
28 /** デフォルトの出力バッファサイズ(単位:byte)。 */
29 public static final int DEFBUFSZ_BYTE = 128;
32 private final CharsetEncoder encoder;
33 private CharBuffer cbuf = CharBuffer.allocate(DEFBUFSZ_CHAR);
34 private byte[] barray = new byte[DEFBUFSZ_BYTE];
35 private ByteBuffer bbuf = ByteBuffer.wrap(this.barray);
37 private CharSequence textData;
38 private int textLength;
44 * @param encoder エンコーダ
45 * @throws NullPointerException 引数がnull
47 public TextExporter(CharsetEncoder encoder) throws NullPointerException{
50 if(encoder == null) throw new NullPointerException();
51 this.encoder = encoder;
52 this.encoder.onMalformedInput(CodingErrorAction.REPORT);
53 this.encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
62 public TextExporter(Charset cs){
63 this(cs.newEncoder());
71 public CharsetEncoder getEncoder(){
77 * @param newSize バッファサイズ。(単位:char)
78 * @throws IllegalArgumentException サイズ指定が正で無かった。
80 public void setCharBufSize(int newSize)
81 throws IllegalArgumentException {
82 if(newSize <= 0) throw new IllegalArgumentException();
83 this.cbuf = CharBuffer.allocate(newSize);
90 * 最低限必要な出力バッファサイズはエンコード設定により異なる。
91 * @param newSize バッファサイズ。(単位:byte)
92 * @throws IllegalArgumentException サイズ指定が小さすぎる。
94 public void setByteBufSize(int newSize)
95 throws IllegalArgumentException {
96 float ratio = this.encoder.maxBytesPerChar();
97 int minSz = (int)( StrictMath.floor(ratio) );
98 if(newSize < minSz) throw new IllegalArgumentException();
99 this.barray = new byte[newSize];
100 this.bbuf = ByteBuffer.wrap(this.barray);
106 * 与えられた文字列をエンコードしてストリームに出力する。
110 * @throws IOException 出力エラー
111 * @throws CharacterCodingException エンコードエラー
113 public int dumpText(CharSequence text, OutputStream os)
114 throws IOException, CharacterCodingException {
115 this.textData = text;
119 total = dumpTextImpl(os);
121 this.textData = null;
128 * 文字列をエンコードしてストリームに出力する。
131 * @throws IOException 出力エラー
132 * @throws CharacterCodingException エンコードエラー
134 private int dumpTextImpl(OutputStream os)
135 throws IOException, CharacterCodingException {
142 CoderResult result = encode();
143 if(result.isUnderflow()){
145 if( ! hasMoreInput() ){
146 total += sweepByteBuffer(os);
149 }else if(result.isOverflow()){
150 total += sweepByteBuffer(os);
152 }else if(result.isError()){
153 result.throwException();
165 private void reset(){
169 this.encoder.reset();
171 this.textLength = this.textData.length();
178 * 入力バッファにまだ入力していない文字があるか判定する。
179 * @return 入力バッファにまだ入力していない文字があればtrue
181 private boolean hasMoreInput(){
182 if(this.inPos < this.textLength) return true;
188 * <p>入力バッファが一杯になるか入力文字列がなくなるまでバッファが埋められる。
190 private void loadCharBuffer(){
191 while(this.cbuf.hasRemaining() && hasMoreInput()){
192 char ch = this.textData.charAt(this.inPos++);
203 private CoderResult encode(){
205 if(hasMoreInput()) endOfInput = false;
206 else endOfInput = true;
209 result = this.encoder.encode(this.cbuf, this.bbuf, endOfInput);
217 * @throws IOException 出力エラー
219 private int sweepByteBuffer(OutputStream os) throws IOException{
222 int total = this.bbuf.remaining();
223 os.write(this.barray, 0, total);
234 * @throws IOException 出力エラー
235 * @throws CharacterCodingException エンコーディングエラー
237 private int flush(OutputStream os)
238 throws IOException, CharacterCodingException {
243 result = this.encoder.flush(this.bbuf);
244 if(result.isError()) result.throwException();
246 total += sweepByteBuffer(os);
248 }while( ! result.isUnderflow() );
254 * 与えられた文字列のエンコード結果を格納先バイトストリームへ格納する。
255 * <p>エンコード結果は格納先ストリームに追記される。
257 * @param bos 格納先ストリーム
258 * @return エンコードしたバイト数。
259 * @throws CharacterCodingException エンコードエラー
261 @SuppressWarnings("PMD.AvoidRethrowingException")
262 public int encodeToByteStream(CharSequence text,
263 ByteArrayOutputStream bos )
264 throws CharacterCodingException {
267 result = dumpText(text, bos);
268 }catch(CharacterCodingException e){
270 }catch(IOException e){
273 throw new AssertionError(e);