OSDN Git Service

remove MIN_INBUFSZ check because Inf-loop auto test
[jindolf/JinParser.git] / src / main / java / jp / sourceforge / jindolf / parser / SjisDecoder.java
1 /*
2  * stream decoder for Shift_JIS
3  *
4  * License : The MIT License
5  * Copyright(c) 2009 olyutorskii
6  */
7
8 package jp.sourceforge.jindolf.parser;
9
10 import java.io.IOException;
11 import java.nio.ByteBuffer;
12 import java.nio.charset.CoderResult;
13
14 /**
15  * Shift_JISバイト列のデコードエラーに特化した、
16  * {@link StreamDecoder}の派生クラス。
17  *
18  * <p>Java実行系の細かな仕様差異による
19  * デコードエラー出現パターンゆらぎの正規化を行う。
20  *
21  * <p>0x5Cが{@literal U+005C}にデコードされるか
22  * {@literal U+00A5}にデコードされるかはJava実行系の実装依存。
23  *
24  * @see <a href="http://www.iana.org/assignments/character-sets">
25  * CHARACTER SETS</a>
26  */
27 public class SjisDecoder extends StreamDecoder{
28
29     /**
30      * コンストラクタ。
31      */
32     public SjisDecoder(){
33         this(BYTEBUF_DEFSZ, CHARBUF_DEFSZ);
34         return;
35     }
36
37     /**
38      * コンストラクタ。
39      *
40      * @param inbufSz 入力バッファサイズ
41      * @param outbufSz 出力バッファサイズ
42      * @throws IllegalArgumentException バッファサイズが小さすぎる。
43      */
44     public SjisDecoder(int inbufSz, int outbufSz)
45             throws IllegalArgumentException{
46         super(ShiftJis.CHARSET.newDecoder(), inbufSz, outbufSz);
47         return;
48     }
49
50     /**
51      * 1バイトのエラーをUnmap系2バイトエラーに統合できないか試す。
52      *
53      * <p>必要に応じて1バイト以上の追加先読みを行う。
54      *
55      * <p>バイト列 {0x85,0x40}(未割り当て9区の文字) を、
56      * 1バイトのエラーと文字@に分離するJava実行系への対処。
57      *
58      * @param result デコード異常系
59      * @return 修正されたデコード異常系。修正がなければ引数と同じものを返す。
60      * @throws IOException 入力エラー
61      */
62     private CoderResult modify1ByteError(CoderResult result)
63             throws IOException {
64         assert result.length() == 1;
65
66         ByteBuffer inbuffer = getByteBuffer();
67
68         if(inbuffer.remaining() < 2){
69             fillByteBuffer();
70         }
71         // 入力バイト列の最後がこの1バイトエラーだった場合。
72         if(inbuffer.remaining() < 2) return result;
73
74         int currPos = inbuffer.position();
75         int nextPos = currPos + 1;
76
77         // 絶対的get
78         byte curr = inbuffer.get(currPos);
79         byte next = inbuffer.get(nextPos);
80
81         CoderResult newResult;
82         if( ShiftJis.isShiftJIS(curr, next) ){
83             newResult = CoderResult.unmappableForLength(2);
84         }else{
85             newResult = result;
86         }
87
88         return newResult;
89     }
90
91     /**
92      * 2バイトのエラーを1バイトに分割できないか試す。
93      *
94      * <p>※ バイト列"FF:32" のShift_JISデコードに際して、
95      * 2バイト長のデコードエラーを返す1.6系実行系が存在する。
96      *
97      * @param result デコード異常系
98      * @return 修正されたデコード異常系。修正がなければ引数と同じものを返す。
99      */
100     private CoderResult modify2ByteError(CoderResult result){
101         assert result.length() == 2;
102
103         ByteBuffer inbuffer = getByteBuffer();
104         assert inbuffer.remaining() >= 2;
105
106         int currPos = inbuffer.position();
107         int nextPos = currPos + 1;
108
109         byte curr = inbuffer.get(currPos);    // 絶対的get
110         byte next = inbuffer.get(nextPos);
111
112         CoderResult newResult;
113         if( ! ShiftJis.isShiftJIS(curr, next) ){
114             newResult = CoderResult.malformedForLength(1);
115         }else{
116             newResult = result;
117         }
118
119         return newResult;
120     }
121
122     /**
123      * {@inheritDoc}
124      *
125      * <p>シフトJISデコードエラー出現パターンの
126      * ランタイム実装による差異を吸収する。
127      *
128      * @param result {@inheritDoc}
129      * @return {@inheritDoc}
130      * @throws IOException {@inheritDoc}
131      */
132     @Override
133     protected CoderResult modifyErrorLength(CoderResult result)
134             throws IOException{
135         int errorLength = result.length();
136
137         CoderResult newResult;
138         switch (errorLength) {
139         case 1:
140             newResult = modify1ByteError(result);
141             break;
142         case 2:
143             newResult = modify2ByteError(result);
144             break;
145         default:
146             newResult = result;
147             break;
148         }
149
150         return newResult;
151     }
152
153 }