4 * License : The MIT License
\r
5 * Copyright(c) 2010 MikuToga Partners
\r
8 package jp.sourceforge.mikutoga.pmd.pmdexporter;
\r
10 import java.io.IOException;
\r
11 import java.io.OutputStream;
\r
12 import java.nio.BufferOverflowException;
\r
13 import java.nio.ByteBuffer;
\r
14 import java.nio.ByteOrder;
\r
15 import java.nio.CharBuffer;
\r
16 import java.nio.charset.Charset;
\r
17 import java.nio.charset.CharsetEncoder;
\r
18 import java.nio.charset.CoderResult;
\r
19 import java.nio.charset.CodingErrorAction;
\r
24 public abstract class AbstractExporter {
\r
26 private static final Charset CS_WIN31J = Charset.forName("windows-31j");
\r
28 private static final String ERRMSG_TOOLONGTEXT = "too long text";
\r
29 private static final String ERRMSG_INVUCSSEQ = "invalid unicode sequence";
\r
30 private static final String ERRMSG_NONWIN31J = "no character in win31j";
\r
32 private static final int BYTES_SHORT = Short .SIZE / Byte.SIZE;
\r
33 private static final int BYTES_INT = Integer.SIZE / Byte.SIZE;
\r
34 private static final int BYTES_FLOAT = Float .SIZE / Byte.SIZE;
\r
36 private static final int BUFSZ_BYTE = 512;
\r
37 private static final int BUFSZ_CHAR = 512;
\r
39 private final OutputStream ostream;
\r
41 private final byte[] barray;
\r
42 private final ByteBuffer bbuf;
\r
44 private final CharBuffer cbuf;
\r
45 private final CharsetEncoder encoder;
\r
50 * @param stream 出力ストリーム
\r
51 * @throws NullPointerException 引数がnull
\r
53 protected AbstractExporter(OutputStream stream)
\r
54 throws NullPointerException{
\r
57 if(stream == null) throw new NullPointerException();
\r
58 this.ostream = stream;
\r
60 this.barray = new byte[BUFSZ_BYTE];
\r
61 this.bbuf = ByteBuffer.wrap(this.barray);
\r
62 this.bbuf.order(ByteOrder.LITTLE_ENDIAN);
\r
64 this.cbuf = CharBuffer.allocate(BUFSZ_CHAR);
\r
65 this.encoder = CS_WIN31J.newEncoder();
\r
66 this.encoder.onMalformedInput(CodingErrorAction.REPORT);
\r
67 this.encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
\r
68 this.encoder.reset();
\r
75 * I/O効率とデバッグ効率のバランスを考え、ご利用は計画的に。
\r
76 * @throws IOException 出力エラー
\r
78 protected void flush() throws IOException{
\r
79 this.ostream.flush();
\r
86 * @throws IOException 出力エラー
\r
88 protected void dumpByte(byte bVal) throws IOException{
\r
89 this.ostream.write((int)bVal);
\r
95 * byte値に収まらない上位ビットはそのまま捨てられる。
\r
97 * @throws IOException 出力エラー
\r
99 protected void dumpByte(int iVal) throws IOException{
\r
100 dumpByte((byte)iVal);
\r
106 * @param sVal short値
\r
107 * @throws IOException 出力エラー
\r
109 protected void dumpShort(short sVal) throws IOException{
\r
111 this.bbuf.putShort(sVal);
\r
112 this.ostream.write(this.barray, 0, BYTES_SHORT);
\r
117 * int値をshort値で出力する。
\r
118 * short値に収まらない上位ビットはそのまま捨てられる。
\r
120 * @throws IOException 出力エラー
\r
122 protected void dumpShort(int iVal) throws IOException{
\r
123 dumpShort((short)iVal);
\r
130 * @throws IOException 出力エラー
\r
132 protected void dumpInt(int iVal) throws IOException{
\r
134 this.bbuf.putInt(iVal);
\r
135 this.ostream.write(this.barray, 0, BYTES_INT);
\r
141 * @param fVal float値
\r
142 * @throws IOException 出力エラー
\r
144 protected void dumpFloat(float fVal) throws IOException{
\r
146 this.bbuf.putFloat(fVal);
\r
147 this.ostream.write(this.barray, 0, BYTES_FLOAT);
\r
152 * 文字列をwindows-31jエンコーディングで出力する。
\r
154 * @return 出力されたbyte総数。
\r
155 * @throws IOException 出力エラー
\r
156 * @throws IllegalPmdTextException 文字エンコーディングに関するエラー
\r
158 protected int dumpCharSequence(CharSequence seq)
\r
159 throws IOException, IllegalPmdTextException{
\r
160 encodeToByteBuffer(seq);
\r
162 int length = dumpByteBuffer();
\r
167 * windows-31jにエンコーディングした文字列を内部バッファに蓄積する。
\r
169 * @throws IllegalPmdTextException 文字エンコーディングに関するエラー。
\r
172 * <li>入力文字列がUnicodeとしてすでにおかしい。
\r
173 * (サロゲートペアがペアになってないなど)
\r
174 * <li>windows-31jにない文字をエンコーディングしようとした
\r
175 * <li>エンコーディング結果が内部バッファに収まらなかった。
\r
179 private void encodeToByteBuffer(CharSequence seq)
\r
180 throws IllegalPmdTextException{
\r
183 this.cbuf.append(seq);
\r
184 }catch(BufferOverflowException e){
\r
185 throw new IllegalPmdTextException(ERRMSG_TOOLONGTEXT);
\r
191 CoderResult result = this.encoder.encode(this.cbuf, this.bbuf, true);
\r
192 if( ! result.isUnderflow()){
\r
193 if(result.isOverflow()){
\r
194 throw new IllegalPmdTextException(ERRMSG_TOOLONGTEXT);
\r
195 }else if(result.isMalformed()){
\r
196 throw new IllegalPmdTextException(ERRMSG_INVUCSSEQ);
\r
197 }else if(result.isUnmappable()){
\r
198 throw new IllegalPmdTextException(ERRMSG_NONWIN31J);
\r
201 throw new AssertionError();
\r
209 * 内部バッファに蓄積されたbyte値並びを出力する。
\r
210 * @return 出力されたbyte数
\r
211 * @throws IOException 出力エラー
\r
213 private int dumpByteBuffer() throws IOException{
\r
214 int offset = this.bbuf.position();
\r
215 int limit = this.bbuf.limit();
\r
216 int length = limit - offset;
\r
217 this.ostream.write(this.barray, offset, length);
\r
219 this.bbuf.position(limit);
\r