4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sfjp.mikutoga.bin.export;
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;
53 this.encoder.onMalformedInput(CodingErrorAction.REPORT);
54 this.encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
66 public TextExporter(Charset cs){
67 this(cs.newEncoder());
75 public CharsetEncoder getEncoder(){
81 * @param newSize バッファサイズ。(単位:char)
82 * @throws IllegalArgumentException サイズ指定が正で無かった。
84 public void setCharBufSize(int newSize)
85 throws IllegalArgumentException {
86 if(newSize <= 0) throw new IllegalArgumentException();
88 this.cbuf = CharBuffer.allocate(newSize);
96 * 最低限必要な出力バッファサイズはエンコード設定により異なる。
97 * @param newSize バッファサイズ。(単位:byte)
98 * @throws IllegalArgumentException サイズ指定が小さすぎる。
100 public void setByteBufSize(int newSize)
101 throws IllegalArgumentException {
102 float ratio = this.encoder.maxBytesPerChar();
103 int minSz = (int)( StrictMath.floor(ratio) );
104 if(newSize < minSz) throw new IllegalArgumentException();
106 this.barray = new byte[newSize];
107 this.bbuf = ByteBuffer.wrap(this.barray);
114 * 与えられた文字列をエンコードしてストリームに出力する。
118 * @throws IOException 出力エラー
119 * @throws CharacterCodingException エンコードエラー
121 public int dumpText(CharSequence text, OutputStream os)
122 throws IOException, CharacterCodingException {
123 this.textData = text;
127 total = dumpTextImpl(os);
129 this.textData = null;
136 * 文字列をエンコードしてストリームに出力する。
139 * @throws IOException 出力エラー
140 * @throws CharacterCodingException エンコードエラー
142 private int dumpTextImpl(OutputStream os)
143 throws IOException, CharacterCodingException {
150 CoderResult result = encode();
151 if(result.isUnderflow()){
153 if( ! hasMoreInput() ){
154 total += sweepByteBuffer(os);
157 }else if(result.isOverflow()){
158 total += sweepByteBuffer(os);
160 }else if(result.isError()){
161 result.throwException();
173 private void reset(){
177 this.encoder.reset();
179 this.textLength = this.textData.length();
186 * 入力バッファにまだ入力していない文字があるか判定する。
187 * @return 入力バッファにまだ入力していない文字があればtrue
189 private boolean hasMoreInput(){
190 if(this.inPos < this.textLength) return true;
198 * 入力文字列がなくなるまでバッファが埋められる。
200 private void loadCharBuffer(){
201 while(this.cbuf.hasRemaining() && hasMoreInput()){
202 char ch = this.textData.charAt(this.inPos++);
213 private CoderResult encode(){
215 if(hasMoreInput()) endOfInput = false;
216 else endOfInput = true;
219 result = this.encoder.encode(this.cbuf, this.bbuf, endOfInput);
227 * @throws IOException 出力エラー
229 private int sweepByteBuffer(OutputStream os) throws IOException{
232 int total = this.bbuf.remaining();
233 os.write(this.barray, 0, total);
244 * @throws IOException 出力エラー
245 * @throws CharacterCodingException エンコーディングエラー
247 private int flush(OutputStream os)
248 throws IOException, CharacterCodingException {
253 result = this.encoder.flush(this.bbuf);
254 if(result.isError()) result.throwException();
256 total += sweepByteBuffer(os);
258 }while( ! result.isUnderflow() );
264 * 与えられた文字列のエンコード結果を格納先バイトストリームへ格納する。
266 * <p>エンコード結果は格納先ストリームに追記される。
269 * @param bos 格納先ストリーム
270 * @return エンコードしたバイト数。
271 * @throws CharacterCodingException エンコードエラー
273 @SuppressWarnings("PMD.AvoidRethrowingException")
274 public int encodeToByteStream(CharSequence text,
275 ByteArrayOutputStream bos )
276 throws CharacterCodingException {
279 result = dumpText(text, bos);
280 }catch(CharacterCodingException e){
282 }catch(IOException e){
285 throw new AssertionError(e);