OSDN Git Service

add modifyErrorLength()
authorOlyutorskii <olyutorskii@users.osdn.me>
Wed, 31 May 2017 12:52:32 +0000 (21:52 +0900)
committerOlyutorskii <olyutorskii@users.osdn.me>
Wed, 31 May 2017 12:52:32 +0000 (21:52 +0900)
src/main/java/jp/sourceforge/jindolf/parser/SjisDecoder.java
src/main/java/jp/sourceforge/jindolf/parser/StreamDecoder.java

index 6908f1a..6a29a26 100644 (file)
@@ -12,11 +12,15 @@ import java.nio.ByteBuffer;
 import java.nio.charset.CoderResult;
 
 /**
- * Shift_JISバイト列のデコードに特化した、{@link StreamDecoder}の派生クラス。
- * Java実行系の細かな仕様差異による
- * デコードエラー出現パターンゆらぎの正規化も行う。
- * 0x5Cが{@literal U+005C}にデコードされるか
+ * Shift_JISバイト列のデコードエラーに特化した、
+ * {@link StreamDecoder}の派生クラス。
+ *
+ * <p>Java実行系の細かな仕様差異による
+ * デコードエラー出現パターンゆらぎの正規化を行う。
+ *
+ * <p>0x5Cが{@literal U+005C}にデコードされるか
  * {@literal U+00A5}にデコードされるかはJava実行系の実装依存。
+ *
  * @see <a href="http://www.iana.org/assignments/character-sets">
  * CHARACTER SETS</a>
  */
@@ -39,6 +43,7 @@ public class SjisDecoder extends StreamDecoder{
 
     /**
      * コンストラクタ。
+     *
      * @param inbufSz 入力バッファサイズ
      * @param outbufSz 出力バッファサイズ
      * @throws IllegalArgumentException バッファサイズが小さすぎる。
@@ -53,87 +58,106 @@ public class SjisDecoder extends StreamDecoder{
     }
 
     /**
-     * 1バイトのエラーを2バイトに統合できないか試す。
+     * 1バイトのエラーをUnmap系2バイトエラーに統合できないか試す。
+     *
+     * <p>必要に応じて1バイト以上の追加先読みを行う。
+     *
+     * <p>バイト列 {0x85,0x40}(未割り当て9区の文字) を、
+     * 1バイトのエラーと文字@に分離するJava実行系への対処。
+     *
      * @param result デコード異常系
      * @return 修正されたデコード異常系。修正がなければ引数と同じものを返す。
      * @throws IOException 入力エラー
      */
     private CoderResult modify1ByteError(CoderResult result)
             throws IOException {
-        ByteBuffer inbuffer = getByteBuffer();
+        assert result.length() == 1;
 
-        int currPos;
-        int nextPos;
+        ByteBuffer inbuffer = getByteBuffer();
 
-        currPos = inbuffer.position();
-        nextPos = currPos + 1;
-        if(nextPos >= inbuffer.limit()){
+        if(inbuffer.remaining() < 2){
             fillByteBuffer();
-            currPos = inbuffer.position();
-            nextPos = currPos + 1;
         }
+        // 入力バイト列の最後がこの1バイトエラーだった場合。
+        if(inbuffer.remaining() < 2) return result;
 
-        // 入力バイト列の最後がこのデコードエラーだった場合。
-        if(nextPos >= inbuffer.limit()) return result;
+        int currPos = inbuffer.position();
+        int nextPos = currPos + 1;
 
-        byte curr = inbuffer.get(currPos);    // 絶対的get
+        // 絶対的get
+        byte curr = inbuffer.get(currPos);
         byte next = inbuffer.get(nextPos);
+
+        CoderResult newResult;
         if( ShiftJis.isShiftJIS(curr, next) ){
-            return CoderResult.unmappableForLength(2);
+            newResult = CoderResult.unmappableForLength(2);
+        }else{
+            newResult = result;
         }
 
-        return result;
+        return newResult;
     }
 
     /**
      * 2バイトのエラーを1バイトに分割できないか試す。
-     * ※ バイト列"FF:32" のShift_JISデコードに際して、
+     *
+     * <p>※ バイト列"FF:32" のShift_JISデコードに際して、
      * 2バイト長のデコードエラーを返す1.6系実行系が存在する。
+     *
      * @param result デコード異常系
      * @return 修正されたデコード異常系。修正がなければ引数と同じものを返す。
      */
     private CoderResult modify2ByteError(CoderResult result){
-        ByteBuffer inbuffer = getByteBuffer();
+        assert result.length() == 2;
 
-        int currPos;
-        int nextPos;
+        ByteBuffer inbuffer = getByteBuffer();
+        assert inbuffer.remaining() >= 2;
 
-        currPos = inbuffer.position();
-        nextPos = currPos + 1;
+        int currPos = inbuffer.position();
+        int nextPos = currPos + 1;
 
         byte curr = inbuffer.get(currPos);    // 絶対的get
         byte next = inbuffer.get(nextPos);
+
+        CoderResult newResult;
         if( ! ShiftJis.isShiftJIS(curr, next) ){
-            return CoderResult.malformedForLength(1);
+            newResult = CoderResult.malformedForLength(1);
+        }else{
+            newResult = result;
         }
 
-        return result;
+        return newResult;
     }
 
     /**
      * {@inheritDoc}
-     * ライブラリ実装によるシフトJISデコードエラー出現パターンの
-     * 差異を吸収する。
+     *
+     * <p>シフトJISデコードエラー出現パターンの
+     * ランタイム実装による差異を吸収する。
+     *
      * @param result {@inheritDoc}
      * @return {@inheritDoc}
      * @throws IOException {@inheritDoc}
      */
     @Override
-    protected int chopErrorSequence(CoderResult result)
+    protected CoderResult modifyErrorLength(CoderResult result)
             throws IOException{
         int errorLength = result.length();
 
         CoderResult newResult;
-        if(errorLength == 1){
+        switch (errorLength) {
+        case 1:
             newResult = modify1ByteError(result);
-        }else if(errorLength == 2){
+            break;
+        case 2:
             newResult = modify2ByteError(result);
-        }else{
-            assert false;
-            return -1;
+            break;
+        default:
+            newResult = result;
+            break;
         }
 
-        return super.chopErrorSequence(newResult);
+        return newResult;
     }
 
 }
index 5f0a0a0..775e14a 100644 (file)
@@ -314,6 +314,7 @@ public class StreamDecoder{
             // デコードエラー出現
             if(decodeResult.isError()){
                 notifyText();
+                decodeResult = modifyErrorLength(decodeResult);
                 notifyError(decodeResult);
                 continue;
             }
@@ -352,6 +353,30 @@ public class StreamDecoder{
     }
 
     /**
+     * エラーの長さ(バイト列長)を修正する。
+     *
+     * <p>文字コード毎の事情に特化した異常系実装を目的とする。
+     * デフォルト実装では引数をそのまま返す。
+     *
+     * <p>バイト列を先読みすることで、
+     * さらに長いエラー情報を再構成してもよい。
+     *
+     * <p>エラー情報を前方に縮小することで、
+     * エラーとして扱われるはずだったバイト列後部は
+     * 再度デコード処理の対象として扱われる。
+     *
+     * @param result 修正元エラー情報。
+     * @return 修正後エラー情報。引数と同じ場合もありうる。
+     * (修正がない場合など)
+     * @throws IOException バイト列読み込みエラー
+     */
+    protected CoderResult modifyErrorLength(CoderResult result)
+            throws IOException{
+        CoderResult newResult = result;
+        return newResult;
+    }
+
+    /**
      * 不適切なバッファサイズ由来の無限ループを検出し例外を投げる。
      *
      * <p>検出しなければ何もしない。