OSDN Git Service

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