4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sourceforge.mikutoga.binio;
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.nio.ByteBuffer;
13 import java.nio.ByteOrder;
14 import java.nio.charset.CharacterCodingException;
15 import java.nio.charset.Charset;
16 import java.text.MessageFormat;
19 * バイナリデータの出力を行う汎用エクスポーター。
20 * <p>デフォルトではリトルエンディアン形式で出力される。
22 public class BinaryExporter {
24 private static final Charset CS_UTF16LE = Charset.forName("UTF-16LE");
25 private static final Charset CS_WIN31J = Charset.forName("windows-31j");
27 private static final String ERRMSG_ILLENC = "illegal encoding";
28 private static final String ERRMSG_TOOLONGTX =
30 + "text \"{0}\" needs {1}bytes encoded but limit={2}bytes";
32 private static final int MASK_16 = 0xffff;
34 private static final int BYTES_SHORT = Short .SIZE / Byte.SIZE;
35 private static final int BYTES_INT = Integer .SIZE / Byte.SIZE;
36 private static final int BYTES_LONG = Long .SIZE / Byte.SIZE;
37 private static final int BYTES_FLOAT = Float .SIZE / Byte.SIZE;
38 private static final int BYTES_DOUBLE = Double .SIZE / Byte.SIZE;
40 private static final int BUFSZ_PRIM = BYTES_DOUBLE;
43 private final OutputStream ostream;
45 private final byte[] barray;
46 private final ByteBuffer primbuf;
48 private final TextExporter texporter_w31j;
49 private final TextExporter texporter_u16le;
50 private final FeedableOutputStream xos;
55 * @param ostream 出力ストリーム
56 * @throws NullPointerException 引数がnull
58 public BinaryExporter(OutputStream ostream) throws NullPointerException{
61 if(ostream == null) throw new NullPointerException();
62 this.ostream = ostream;
64 this.barray = new byte[BUFSZ_PRIM];
65 this.primbuf = ByteBuffer.wrap(this.barray);
66 this.primbuf.order(ByteOrder.LITTLE_ENDIAN);
70 this.texporter_w31j = new TextExporter(CS_WIN31J);
71 this.texporter_u16le = new TextExporter(CS_UTF16LE);
72 this.xos = new FeedableOutputStream();
80 * @param order バイトオーダー
82 public void setOrder(ByteOrder order){
83 this.primbuf.order(order);
89 * @return 設定されたバイトオーダー
91 public ByteOrder getOrder(){
92 return this.primbuf.order();
97 * @throws IOException 出力エラー
99 public void close() throws IOException{
100 this.ostream.close();
106 * I/O効率とデバッグ効率のバランスを考え、ご利用は計画的に。
108 * @throws IOException 出力エラー
110 public BinaryExporter flush() throws IOException{
111 this.ostream.flush();
119 * @throws IOException 出力エラー
121 public BinaryExporter dumpByte(byte bVal) throws IOException{
122 this.ostream.write((int)bVal);
128 * @param iVal int値。上位24bitは捨てられる。
130 * @throws IOException 出力エラー
132 public BinaryExporter dumpByte(int iVal) throws IOException{
133 this.ostream.write(iVal);
141 * @throws IOException 出力エラー
143 public BinaryExporter dumpByteArray(byte[] array)
145 dumpByteArray(array, 0, array.length);
152 * @param offset 出力開始位置
153 * @param length 出力バイト数
155 * @throws IOException 出力エラー
157 public BinaryExporter dumpByteArray(byte[] array, int offset, int length)
159 this.ostream.write(array, offset, length);
165 * @param length 出力バイト数
166 * @throws IOException 出力エラー
168 private void dumpBuffer(int length) throws IOException{
169 this.ostream.write(this.barray, 0, length);
177 * @throws IOException 出力エラー
179 @SuppressWarnings("PMD.AvoidUsingShortType")
180 public BinaryExporter dumpShort(short sVal) throws IOException{
181 this.primbuf.putShort(0, sVal);
182 dumpBuffer(BYTES_SHORT);
188 * @param iVal int値。上位16bitは捨てられる。
190 * @throws IOException 出力エラー
192 @SuppressWarnings("PMD.AvoidUsingShortType")
193 public BinaryExporter dumpShort(int iVal) throws IOException{
194 short sVal = (short)(iVal & MASK_16);
203 * @throws IOException 出力エラー
205 public BinaryExporter dumpInt(int iVal) throws IOException{
206 this.primbuf.putInt(0, iVal);
207 dumpBuffer(BYTES_INT);
215 * @throws IOException 出力エラー
217 public BinaryExporter dumpLong(long lVal) throws IOException{
218 this.primbuf.putLong(0, lVal);
219 dumpBuffer(BYTES_LONG);
227 * @throws IOException 出力エラー
229 public BinaryExporter dumpFloat(float fVal) throws IOException{
230 this.primbuf.putFloat(0, fVal);
231 dumpBuffer(BYTES_FLOAT);
237 * @param dVal double値
239 * @throws IOException 出力エラー
241 public BinaryExporter dumpDouble(double dVal) throws IOException{
242 this.primbuf.putDouble(0, dVal);
243 dumpBuffer(BYTES_DOUBLE);
249 * @param filler byte型配列によるパディングデータの並び。
250 * <p>指定パディング長より長い部分は出力されない。
251 * 指定パディング長に満たない場合は最後の要素が繰り返し出力される。
252 * <p>配列長が0の場合は何も出力されない。
253 * @param fillerLength パディング長。
254 * <p>パディング長が0以下の場合は何も出力されない。
256 * @throws IOException 出力エラー
258 public BinaryExporter dumpFiller(byte[] filler, int fillerLength)
260 if(filler.length <= 0 || fillerLength <= 0){
264 byte lastData = filler[filler.length - 1];
267 for(int remain = fillerLength; remain > 0; remain--){
269 if(fillerIdx < filler.length) bVal = filler[fillerIdx++];
270 else bVal = lastData;
278 * Windows31J文字列をを固定バイト長で出力する。
279 * 固定バイト長に満たない箇所はパディングデータが詰められる。
281 * @param fixedLength 固定バイト長。0以下の場合は無制限。
282 * @param filler 詰め物パディングデータ
284 * @throws IOException 出力エラー
285 * @throws IllegalTextExportException テキスト出力エラー。
287 * もしくは不正なエンコードが行われたかのいずれか。
289 public BinaryExporter dumpFixedW31j(CharSequence text,
292 throws IOException, IllegalTextExportException{
298 this.texporter_w31j.encodeToByteStream(text, this.xos);
299 }catch(CharacterCodingException e){
300 throw new IllegalTextExportException(ERRMSG_ILLENC, e);
303 if( 0 < fixedLength && fixedLength < encodedSize ){
305 MessageFormat.format(ERRMSG_TOOLONGTX,
306 text, encodedSize, fixedLength);
307 throw new IllegalTextExportException(message);
310 int xferred = this.xos.feedStored(this.ostream);
312 int remain = fixedLength - xferred;
314 dumpFiller(filler, remain);
321 * UTF16-LE文字列をホレリス形式で出力する。
322 * UTF16-LEエンコード結果のバイト長を
323 * 4byte整数としてリトルエンディアンで出力した後に、
324 * エンコード結果のバイト列が出力される。
327 * @throws IOException 出力エラー
328 * @throws IllegalTextExportException テキスト出力エラー。
330 * もしくは不正なエンコードが行われたかのいずれか。
332 public int dumpHollerithUtf16LE(CharSequence text)
333 throws IOException, IllegalTextExportException{
339 this.texporter_u16le.encodeToByteStream(text, this.xos);
340 }catch(CharacterCodingException e){
341 throw new IllegalTextExportException(ERRMSG_ILLENC, e);
344 dumpInt(encodedSize);
346 int xferred = this.xos.feedStored(this.ostream);
347 assert xferred == encodedSize;