OSDN Git Service

パッケージ変更。テスト整備。
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / bin / parser / TextDecoder.java
1 /*
2  * character decoder
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.bin.parser;
9
10 import java.nio.ByteBuffer;
11 import java.nio.CharBuffer;
12 import java.nio.charset.CharacterCodingException;
13 import java.nio.charset.Charset;
14 import java.nio.charset.CharsetDecoder;
15 import java.nio.charset.CoderResult;
16 import java.nio.charset.CodingErrorAction;
17
18 /**
19  * 文字デコーダー。
20  * <p>あらかじめバイト長が既知であるバイトバッファを読み取り、
21  * 文字列へのデコード結果を返す。
22  * <p>デコード対象のバイト列が全てメモリ上に展開される必要があるので、
23  * 巨大なテキストのデコードには不適当。
24  * <p>入力バイト値0x00以降をデコード処理の対象から外す
25  * 「ゼロチョップモード」を備える。
26  * デフォルトではゼロチョップモードはオフ。
27  * ゼロチョップモードはUTF16などのデコーディング時に使ってはならない。
28  */
29 public class TextDecoder {
30
31     private final CharsetDecoder decoder;
32
33     private CharBuffer charBuffer;
34
35     private boolean chopZero = false;
36
37
38     /**
39      * コンストラクタ。
40      * @param cs キャラクタセット
41      */
42     public TextDecoder(Charset cs){
43         this(cs.newDecoder());
44         return;
45     }
46
47     /**
48      * コンストラクタ。
49      * @param decoder デコーダ
50      */
51     public TextDecoder(CharsetDecoder decoder){
52         super();
53
54         this.decoder = decoder;
55         this.decoder.reset();
56         this.decoder.onMalformedInput     (CodingErrorAction.REPORT);
57         this.decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
58
59         return;
60     }
61
62     /**
63      * 指定されたバイト長のデコードに必要な出力バッファを用意する。
64      * <p>既存バッファで足りなければ新たに確保し直す。
65      * @param byteLength 入力バイト長
66      * @return 出力バッファ長。(キャラクタ単位)
67      */
68     protected int prepareCharBuffer(int byteLength){
69         float maxCharsPerByte = this.decoder.maxCharsPerByte();
70         int maxChars = (int)( byteLength * maxCharsPerByte ) + 1;
71
72         if(this.charBuffer != null){
73             int capacity = this.charBuffer.capacity();
74             if(capacity >= maxChars){
75                 return capacity;
76             }
77         }
78
79         this.charBuffer = CharBuffer.allocate(maxChars);
80
81         return maxChars;
82     }
83
84     /**
85      * ゼロチョップモードを設定する。
86      * ゼロチョップモードをオンにすると、
87      * 入力バイト値0x00以降はデコード対象外となる。
88      * @param chop trueならゼロチョップモードオン
89      */
90     public void setZeroChopMode(boolean chop){
91         this.chopZero = chop;
92         return;
93     }
94
95     /**
96      * ゼロチョップモードか否か判定する。
97      * @return ゼロチョップモードならtrue
98      */
99     public boolean isZeroChopMode(){
100         return this.chopZero;
101     }
102
103     /**
104      * 入力バイトバッファのバイト値'0'出現以降をチョップする。
105      * ゼロチョップモードでなければ何もしない。
106      * @param bBuf 入力バイトバッファ
107      */
108     protected void chopZeroTermed(ByteBuffer bBuf){
109         if( ! this.chopZero ) return;
110
111         int start = bBuf.position();
112         int limit = bBuf.limit();
113         for(int idx = start; idx < limit; idx++){
114             byte bVal = bBuf.get(idx);
115             if(bVal == 0x00){
116                 bBuf.limit(idx);
117                 break;
118             }
119         }
120
121         return;
122     }
123
124     /**
125      * バイトバッファの文字列デコードを行う。
126      * @param bBuf バイトバッファ
127      * @return デコードされた文字列
128      * @throws CharacterCodingException デコード異常
129      */
130     public String decode(ByteBuffer bBuf) throws CharacterCodingException{
131         chopZeroTermed(bBuf);
132
133         int blen = bBuf.remaining();
134         prepareCharBuffer(blen);
135         this.charBuffer.clear();
136
137         this.decoder.reset();
138         CoderResult decResult;
139         decResult = this.decoder.decode(bBuf, this.charBuffer, true);
140
141         if(decResult.isError()){
142             decResult.throwException();
143             assert false;
144         }
145
146         assert ! decResult.isOverflow();
147
148         String result = this.charBuffer.flip().toString();
149         return result;
150     }
151
152 }