* Copyright(c) 2010 MikuToga Partners
*/
-package jp.sourceforge.mikutoga.parser;
+package jp.sfjp.mikutoga.bin.parser;
import java.io.EOFException;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.UnmappableCharacterException;
/**
- * 各種パーサの共通実装。
+ * 各種バイナリファイルパーサの共通実装。
+ * <p>バイト列、各種プリミティブ型値およびエンコードされた文字列を読み込む。
+ * <p>long,double、およびビッグエンディアン形式のデータは未サポート。
*/
public class CommonParser {
+ private static final String ERRMSG_ILLENC =
+ "illegal character encoding";
+ private static final String ERRMSG_UNMAP =
+ "unmapped character";
+
private static final int BYTES_SHORT = Short .SIZE / Byte.SIZE;
private static final int BYTES_INT = Integer.SIZE / Byte.SIZE;
private static final int BYTES_FLOAT = Float .SIZE / Byte.SIZE;
private final PushbackInputStream is;
private final byte[] readBuffer;
- private final ByteBuffer beBuf;
+// private final ByteBuffer beBuf;
private final ByteBuffer leBuf;
private long position = 0L;
+ private ByteBuffer btextBuf;
+
/**
* コンストラクタ。
this.readBuffer = new byte[BYTES_PRIM];
- this.beBuf = ByteBuffer.wrap(this.readBuffer);
+// this.beBuf = ByteBuffer.wrap(this.readBuffer);
this.leBuf = ByteBuffer.wrap(this.readBuffer);
- this.beBuf.order(ByteOrder.BIG_ENDIAN);
+// this.beBuf.order(ByteOrder.BIG_ENDIAN);
this.leBuf.order(ByteOrder.LITTLE_ENDIAN);
return;
/**
* byte配列を読み込む。
- * 配列要素全ての読み込みが試みられる。
+ * <p>配列要素全ての読み込みが試みられる。
* @param dst 格納先配列
* @throws IOException IOエラー
* @throws NullPointerException 配列がnull
/**
* 内部バッファへ指定バイト数だけ読み込む。
- * @param fillSize
- * @throws IOException
- * @throws MmdEofException
+ * @param fillSize バイト長
+ * @throws IOException IOエラー
+ * @throws MmdEofException 読み込む途中でストリーム終端に達した。
*/
private void fillBuffer(int fillSize)
throws IOException, MmdEofException {
/**
* 符号無し値としてbyte値を読み込み、int型に変換して返す。
- * 符号は拡張されない。(0xffは0x000000ffとなる)
+ * <p>符号は拡張されない。(0xffは0x000000ffとなる)
* @return 読み込まれた値のint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
*/
protected int parseUByteAsInt()
throws IOException, MmdEofException{
- return ((int) parseByte()) & MASK_8BIT;
+ return parseByte() & MASK_8BIT;
}
/**
* byte値を読み込み、boolean型に変換して返す。
- * 0x00は偽、それ以外は真と解釈される。
+ * <p>0x00は偽、それ以外は真と解釈される。
* @return 読み込まれた値のboolean値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
/**
* short値を読み込む。
- * short値はリトルエンディアンで格納されていると仮定される。
+ * <p>short値はリトルエンディアンで格納されていると仮定される。
* @return 読み込んだshort値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
/**
* 符号無し値としてshort値を読み込み、int型に変換して返す。
- * 符号は拡張されない。(0xffffは0x0000ffffとなる)
- * short値はリトルエンディアンで格納されていると仮定される。
+ * <p>符号は拡張されない。(0xffffは0x0000ffffとなる)
+ * <p>short値はリトルエンディアンで格納されていると仮定される。
* @return 読み込まれた値のint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
*/
protected int parseLeUShortAsInt()
throws IOException, MmdEofException{
- return ((int) parseLeShort()) & MASK_16BIT;
+ return parseLeShort() & MASK_16BIT;
}
/**
* int値を読み込む。
- * int値はリトルエンディアンで格納されていると仮定される。
+ * <p>int値はリトルエンディアンで格納されていると仮定される。
* @return 読み込んだint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
/**
* float値を読み込む。
- * float値はリトルエンディアンで格納されていると仮定される。
+ * <p>float値はリトルエンディアンで格納されていると仮定される。
* @return 読み込んだfloat値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
*/
protected String parseString(TextDecoder decoder, int byteLen)
throws IOException, MmdEofException, MmdFormatException {
- byte[] buf = decoder.prepareBuffer(byteLen);
+ if(this.btextBuf == null || this.btextBuf.capacity() < byteLen){
+ this.btextBuf = ByteBuffer.allocate(byteLen);
+ }
+
+ byte[] buf = this.btextBuf.array();
+ this.btextBuf.clear();
parseByteArray(buf, 0, byteLen);
- long basePos = getPosition();
- String result= decoder.decode(basePos, byteLen);
+ this.btextBuf.limit(byteLen);
+
+ String result;
+
+ try{
+ result = decoder.decode(this.btextBuf);
+ }catch(UnmappableCharacterException e){
+ String errmsg = ERRMSG_UNMAP;
+ long errpos = getPosition() - byteLen + e.getInputLength();
+ MmdFormatException ex = new MmdFormatException(errmsg, errpos);
+ ex.initCause(e);
+ throw ex;
+ }catch(MalformedInputException e){
+ String errmsg = ERRMSG_ILLENC;
+ long errpos = getPosition() - byteLen + e.getInputLength();
+ MmdFormatException ex = new MmdFormatException(errmsg, errpos);
+ ex.initCause(e);
+ throw ex;
+ }catch(CharacterCodingException e){ // 状況不明
+ String errmsg = ERRMSG_ILLENC;
+ long errpos = getPosition();
+ MmdFormatException ex = new MmdFormatException(errmsg, errpos);
+ ex.initCause(e);
+ throw ex;
+ }
+
return result;
}