OSDN Git Service

1.105.3-SNAPSHOT版開発開始
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / pmd / pmdexporter / AbstractExporter.java
1 /*\r
2  * abstract exporter\r
3  *\r
4  * License : The MIT License\r
5  * Copyright(c) 2010 MikuToga Partners\r
6  */\r
7 \r
8 package jp.sourceforge.mikutoga.pmd.pmdexporter;\r
9 \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
20 \r
21 /**\r
22  * 抽象化されたエクスポーター共通部。\r
23  */\r
24 public abstract class AbstractExporter {\r
25 \r
26     private static final Charset CS_WIN31J = Charset.forName("windows-31j");\r
27 \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
31 \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
35 \r
36     private static final int BUFSZ_BYTE = 512;\r
37     private static final int BUFSZ_CHAR = 512;\r
38 \r
39     private final OutputStream ostream;\r
40 \r
41     private final byte[] barray;\r
42     private final ByteBuffer bbuf;\r
43 \r
44     private final CharBuffer cbuf;\r
45     private final CharsetEncoder encoder;\r
46 \r
47 \r
48     /**\r
49      * コンストラクタ。\r
50      * @param stream 出力ストリーム\r
51      * @throws NullPointerException 引数がnull\r
52      */\r
53     protected AbstractExporter(OutputStream stream)\r
54             throws NullPointerException{\r
55         super();\r
56 \r
57         if(stream == null) throw new NullPointerException();\r
58         this.ostream = stream;\r
59 \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
63 \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
69 \r
70         return;\r
71     }\r
72 \r
73     /**\r
74      * 出力をフラッシュする。\r
75      * I/O効率とデバッグ効率のバランスを考え、ご利用は計画的に。\r
76      * @throws IOException 出力エラー\r
77      */\r
78     protected void flush() throws IOException{\r
79         this.ostream.flush();\r
80         return;\r
81     }\r
82 \r
83     /**\r
84      * byte値を出力する。\r
85      * @param bVal byte値\r
86      * @throws IOException 出力エラー\r
87      */\r
88     protected void dumpByte(byte bVal) throws IOException{\r
89         this.ostream.write((int)bVal);\r
90         return;\r
91     }\r
92 \r
93     /**\r
94      * int値をbyte値で出力する。\r
95      * byte値に収まらない上位ビットはそのまま捨てられる。\r
96      * @param iVal int値\r
97      * @throws IOException 出力エラー\r
98      */\r
99     protected void dumpByte(int iVal) throws IOException{\r
100         dumpByte((byte)iVal);\r
101         return;\r
102     }\r
103 \r
104     /**\r
105      * short値を出力する。\r
106      * @param sVal short値\r
107      * @throws IOException 出力エラー\r
108      */\r
109     protected void dumpShort(short sVal) throws IOException{\r
110         this.bbuf.clear();\r
111         this.bbuf.putShort(sVal);\r
112         this.ostream.write(this.barray, 0, BYTES_SHORT);\r
113         return;\r
114     }\r
115 \r
116     /**\r
117      * int値をshort値で出力する。\r
118      * short値に収まらない上位ビットはそのまま捨てられる。\r
119      * @param iVal int値\r
120      * @throws IOException 出力エラー\r
121      */\r
122     protected void dumpShort(int iVal) throws IOException{\r
123         dumpShort((short)iVal);\r
124         return;\r
125     }\r
126 \r
127     /**\r
128      * int値を出力する。\r
129      * @param iVal int値\r
130      * @throws IOException 出力エラー\r
131      */\r
132     protected void dumpInt(int iVal) throws IOException{\r
133         this.bbuf.clear();\r
134         this.bbuf.putInt(iVal);\r
135         this.ostream.write(this.barray, 0, BYTES_INT);\r
136         return;\r
137     }\r
138 \r
139     /**\r
140      * float値を出力する。\r
141      * @param fVal float値\r
142      * @throws IOException 出力エラー\r
143      */\r
144     protected void dumpFloat(float fVal) throws IOException{\r
145         this.bbuf.clear();\r
146         this.bbuf.putFloat(fVal);\r
147         this.ostream.write(this.barray, 0, BYTES_FLOAT);\r
148         return;\r
149     }\r
150 \r
151     /**\r
152      * 文字列をwindows-31jエンコーディングで出力する。\r
153      * @param seq 文字列\r
154      * @return 出力されたbyte総数。\r
155      * @throws IOException 出力エラー\r
156      * @throws IllegalPmdTextException 文字エンコーディングに関するエラー\r
157      */\r
158     protected int dumpCharSequence(CharSequence seq)\r
159             throws IOException, IllegalPmdTextException{\r
160         encodeToByteBuffer(seq);\r
161         this.bbuf.flip();\r
162         int length = dumpByteBuffer();\r
163         return length;\r
164     }\r
165 \r
166     /**\r
167      * windows-31jにエンコーディングした文字列を内部バッファに蓄積する。\r
168      * @param seq 文字列\r
169      * @throws IllegalPmdTextException 文字エンコーディングに関するエラー。\r
170      * 考えられる状況としては、\r
171      * <ul>\r
172      * <li>入力文字列がUnicodeとしてすでにおかしい。\r
173      * (サロゲートペアがペアになってないなど)\r
174      * <li>windows-31jにない文字をエンコーディングしようとした\r
175      * <li>エンコーディング結果が内部バッファに収まらなかった。\r
176      * </ul>\r
177      * など。\r
178      */\r
179     private void encodeToByteBuffer(CharSequence seq)\r
180             throws IllegalPmdTextException{\r
181         this.cbuf.clear();\r
182         try{\r
183             this.cbuf.append(seq);\r
184         }catch(BufferOverflowException e){\r
185             throw new IllegalPmdTextException(ERRMSG_TOOLONGTEXT);\r
186         }\r
187         this.cbuf.flip();\r
188 \r
189         this.bbuf.clear();\r
190 \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
199             }else{\r
200                 assert false;\r
201                 throw new AssertionError();\r
202             }\r
203         }\r
204 \r
205         return;\r
206     }\r
207 \r
208     /**\r
209      * 内部バッファに蓄積されたbyte値並びを出力する。\r
210      * @return 出力されたbyte数\r
211      * @throws IOException 出力エラー\r
212      */\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
218 \r
219         this.bbuf.position(limit);\r
220 \r
221         return length;\r
222     }\r
223 \r
224 }\r