OSDN Git Service

パッケージ変更。テスト整備。
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / bin / parser / CommonParser.java
@@ -5,7 +5,7 @@
  * Copyright(c) 2010 MikuToga Partners
  */
 
-package jp.sourceforge.mikutoga.parser;
+package jp.sfjp.mikutoga.bin.parser;
 
 import java.io.EOFException;
 import java.io.IOException;
@@ -13,12 +13,22 @@ import java.io.InputStream;
 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;
@@ -37,11 +47,13 @@ public class CommonParser {
     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;
+
 
     /**
      * コンストラクタ。
@@ -54,10 +66,10 @@ public class CommonParser {
 
         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;
@@ -153,7 +165,7 @@ public class CommonParser {
 
     /**
      * byte配列を読み込む。
-     * 配列要素全ての読み込みが試みられる。
+     * <p>配列要素全ての読み込みが試みられる。
      * @param dst 格納先配列
      * @throws IOException IOエラー
      * @throws NullPointerException 配列がnull
@@ -168,9 +180,9 @@ public class CommonParser {
 
     /**
      * 内部バッファへ指定バイト数だけ読み込む。
-     * @param fillSize
-     * @throws IOException
-     * @throws MmdEofException
+     * @param fillSize バイト長
+     * @throws IOException IOエラー
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。
      */
     private void fillBuffer(int fillSize)
             throws IOException, MmdEofException {
@@ -199,19 +211,19 @@ public class CommonParser {
 
     /**
      * 符号無し値として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 読み込む途中でストリーム終端に達した。
@@ -225,7 +237,7 @@ public class CommonParser {
 
     /**
      * short値を読み込む。
-     * short値はリトルエンディアンで格納されていると仮定される。
+     * <p>short値はリトルエンディアンで格納されていると仮定される。
      * @return 読み込んだshort値
      * @throws IOException IOエラー
      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
@@ -239,20 +251,20 @@ public class CommonParser {
 
     /**
      * 符号無し値として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 読み込む途中でストリーム終端に達した。
@@ -266,7 +278,7 @@ public class CommonParser {
 
     /**
      * float値を読み込む。
-     * float値はリトルエンディアンで格納されていると仮定される。
+     * <p>float値はリトルエンディアンで格納されていると仮定される。
      * @return 読み込んだfloat値
      * @throws IOException IOエラー
      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
@@ -289,10 +301,39 @@ public class CommonParser {
      */
     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;
     }