OSDN Git Service

入力ソースへのアクセスを可能に
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / parser / CommonParser.java
1 /*
2  * common MMD parser
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sourceforge.mikutoga.parser;
9
10 import java.io.IOException;
11 import java.nio.CharBuffer;
12 import java.nio.charset.Charset;
13
14 /**
15  * 各種パーサの共通実装。
16  */
17 public class CommonParser {
18
19     /**
20      * PMDで用いられる文字エンコーディング(windows-31j)。
21      * ほぼShift_JISのスーパーセットと思ってよい。
22      * デコード結果はUCS-2集合に収まるはず。
23      */
24     public static final Charset CS_WIN31J = Charset.forName("windows-31j");
25
26     /** PMXで用いられる文字エンコーディング(UTF-8)。 */
27     public static final Charset CS_UTF8 = Charset.forName("UTF-8");
28
29     /** PMXで用いられる文字エンコーディング(UTF-16のリトルエンディアン)。 */
30     public static final Charset CS_UTF16LE = Charset.forName("UTF-16LE");
31
32     private final MmdSource source;
33
34     private final TextDecoder decoderWin31j  = new TextDecoder(CS_WIN31J);
35     private final TextDecoder decoderUTF8    = new TextDecoder(CS_UTF8);
36     private final TextDecoder decoderUTF16LE = new TextDecoder(CS_UTF16LE);
37
38     /**
39      * コンストラクタ。
40      * @param source 入力ソース
41      */
42     public CommonParser(MmdSource source){
43         super();
44
45         this.source = source;
46
47         this.decoderWin31j .setZeroChopMode(true);
48         this.decoderUTF8   .setZeroChopMode(false);
49         this.decoderUTF16LE.setZeroChopMode(false);
50
51         return;
52     }
53
54     /**
55      * 入力ソースを返す。
56      * @return 入力ソース
57      */
58     protected MmdSource getSource(){
59         return this.source;
60     }
61
62     /**
63      * 入力ソースの読み込み位置を返す。
64      * @return 入力ソースの読み込み位置。単位はbyte。
65      */
66     protected long getPosition(){
67         long result = this.source.getPosition();
68         return result;
69     }
70
71     /**
72      * 入力ソースにまだデータが残っているか判定する。
73      * @return まだ読み込んでいないデータが残っていればtrue
74      * @throws IOException IOエラー
75      * @see MmdSource#hasMore()
76      */
77     protected boolean hasMore() throws IOException{
78         boolean result = this.source.hasMore();
79         return result;
80     }
81
82     /**
83      * 入力ソースを読み飛ばす。
84      * @param skipLength 読み飛ばすバイト数。
85      * @throws IOException IOエラー
86      * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。
87      * @see MmdSource#skip(long)
88      */
89     protected void skip(long skipLength)
90             throws IOException, MmdEofException {
91         long result = this.source.skip(skipLength);
92         if(result != skipLength){
93             throw new MmdEofException(this.source.getPosition());
94         }
95
96         return;
97     }
98
99     /**
100      * 入力ソースを読み飛ばす。
101      * @param skipLength 読み飛ばすバイト数。
102      * @throws IOException IOエラー
103      * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。
104      * @see MmdSource#skip(long)
105      */
106     protected void skip(int skipLength)
107             throws IOException, MmdEofException {
108         skip((long) skipLength);
109     }
110
111     /**
112      * byte値を読み込む。
113      * @return 読み込んだbyte値
114      * @throws IOException IOエラー
115      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
116      * @see MmdSource#parseByte()
117      */
118     protected byte parseByte()
119             throws IOException, MmdEofException{
120         return this.source.parseByte();
121     }
122
123     /**
124      * 符号無し値としてbyte値を読み込み、int型に変換して返す。
125      * 符号は拡張されない。(0xffは0x000000ffとなる)
126      * @return 読み込まれた値のint値
127      * @throws IOException IOエラー
128      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
129      * @see MmdSource#parseUByteAsInteger()
130      */
131     protected int parseUByteAsInteger()
132             throws IOException, MmdEofException{
133         return this.source.parseUByteAsInteger();
134     }
135
136     /**
137      * byte値を読み込み、boolean型に変換して返す。
138      * 0x00は偽、それ以外は真と解釈される。
139      * @return 読み込まれた値のboolean値
140      * @throws IOException IOエラー
141      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
142      * @see MmdSource#parseBoolean()
143      */
144     protected boolean parseBoolean()
145             throws IOException, MmdEofException{
146         return this.source.parseBoolean();
147     }
148
149     /**
150      * short値を読み込む。
151      * short値はリトルエンディアンで格納されていると仮定される。
152      * @return 読み込んだshort値
153      * @throws IOException IOエラー
154      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
155      * @see MmdSource#parseShort()
156      */
157     protected short parseShort()
158             throws IOException, MmdEofException{
159         return this.source.parseShort();
160     }
161
162     /**
163      * 符号無し値としてshort値を読み込み、int型に変換して返す。
164      * 符号は拡張されない。(0xffffは0x0000ffffとなる)
165      * short値はリトルエンディアンで格納されていると仮定される。
166      * @return 読み込まれた値のint値
167      * @throws IOException IOエラー
168      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
169      * @see MmdSource#parseUShortAsInteger()
170      */
171     protected int parseUShortAsInteger()
172             throws IOException, MmdEofException{
173         return this.source.parseUShortAsInteger();
174     }
175
176     /**
177      * int値を読み込む。
178      * int値はリトルエンディアンで格納されていると仮定される。
179      * @return 読み込んだint値
180      * @throws IOException IOエラー
181      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
182      * @see MmdSource#parseInteger()
183      */
184     protected int parseInteger()
185             throws IOException, MmdEofException{
186         return this.source.parseInteger();
187     }
188
189     /**
190      * float値を読み込む。
191      * float値はリトルエンディアンで格納されていると仮定される。
192      * @return 読み込んだfloat値
193      * @throws IOException IOエラー
194      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
195      * @see MmdSource#parseFloat()
196      */
197     protected float parseFloat()
198             throws IOException, MmdEofException{
199         return this.source.parseFloat();
200     }
201
202     /**
203      * byte配列を読み込む。
204      * @param dst 格納先配列
205      * @param offset 読み込み開始オフセット
206      * @param length 読み込みバイト数
207      * @throws IOException IOエラー
208      * @throws NullPointerException 配列がnull
209      * @throws IndexOutOfBoundsException 引数が配列属性と矛盾
210      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
211      * @see MmdSource#parseByteArray(byte[], int, int)
212      */
213     protected void parseByteArray(byte[] dst, int offset, int length)
214             throws IOException,
215                    NullPointerException,
216                    IndexOutOfBoundsException,
217                    MmdEofException {
218         this.source.parseByteArray(dst, offset, length);
219         return;
220     }
221
222     /**
223      * byte配列を読み込む。
224      * 配列要素全ての読み込みが試みられる。
225      * @param dst 格納先配列
226      * @throws IOException IOエラー
227      * @throws NullPointerException 配列がnull
228      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
229      * @see MmdSource#parseByteArray(byte[])
230      */
231     protected void parseByteArray(byte[] dst)
232             throws IOException, NullPointerException, MmdEofException{
233         this.source.parseByteArray(dst);
234         return;
235     }
236
237     /**
238      * float配列を読み込む。
239      * @param dst 格納先配列
240      * @param offset 読み込み開始オフセット
241      * @param length 読み込みfloat要素数
242      * @throws IOException IOエラー
243      * @throws NullPointerException 配列がnull
244      * @throws IndexOutOfBoundsException 引数が配列属性と矛盾
245      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
246      * @see MmdSource#parseFloatArray(float[], int, int)
247      */
248     protected void parseFloatArray(float[] dst, int offset, int length)
249             throws IOException,
250                    NullPointerException,
251                    IndexOutOfBoundsException,
252                    MmdEofException {
253         this.source.parseFloatArray(dst, offset, length);
254         return;
255     }
256
257     /**
258      * float配列を読み込む。
259      * 配列要素全ての読み込みが試みられる。
260      * @param dst 格納先配列
261      * @throws IOException IOエラー
262      * @throws NullPointerException 配列がnull
263      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
264      * @see MmdSource#parseFloatArray(float[])
265      */
266     protected void parseFloatArray(float[] dst)
267             throws IOException, NullPointerException, MmdEofException{
268         this.source.parseFloatArray(dst);
269         return;
270     }
271
272     /**
273      * 指定された最大バイト長に収まるゼロ終端(0x00)文字列を読み込む。
274      * 入力バイト列はwindows-31jエンコーディングとして解釈される。
275      * ゼロ終端以降のデータは無視されるが、
276      * IO入力は指定バイト数だけ読み進められる。
277      * ゼロ終端が見つからないまま指定バイト数が読み込み終わった場合、
278      * そこまでのデータから文字列を構成する。
279      * @param maxlen 読み込みバイト数
280      * @return デコードされた文字列
281      * @throws IOException IOエラー
282      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
283      * @throws MmdFormatException 不正な文字エンコーディングが検出された。
284      */
285     protected String parseZeroTermWin31J(int maxlen)
286             throws IOException,
287                    MmdEofException,
288                    MmdFormatException {
289         CharBuffer encoded =
290                 this.decoderWin31j.parseString(this.source, maxlen);
291
292         String result = encoded.toString();
293
294         return result;
295     }
296
297     /**
298      * 4byte整数によるバイト列長とそれに続くUTF8バイト列を
299      * 文字にデコードする。
300      * @return デコードされた文字列。
301      * @throws IOException IOエラー
302      * @throws MmdEofException 予期せぬ入力終端
303      * @throws MmdFormatException 不正な文字エンコーディングが検出された。
304      */
305     protected String parseHollerithUtf8()
306             throws IOException,
307                    MmdEofException,
308                    MmdFormatException {
309         int byteLen = this.source.parseInteger();
310
311         CharBuffer encoded =
312                 this.decoderUTF8.parseString(this.source, byteLen);
313
314         String result = encoded.toString();
315
316         return result;
317     }
318
319     /**
320      * 4byte整数によるバイト列長とそれに続くUTF16-LEバイト列を
321      * 文字にデコードする。
322      * @return デコードされた文字列。
323      * @throws IOException IOエラー
324      * @throws MmdEofException 予期せぬ入力終端
325      * @throws MmdFormatException 不正な文字エンコーディングが検出された。
326      */
327     protected String parseHollerithUtf16LE()
328             throws IOException,
329                    MmdEofException,
330                    MmdFormatException {
331         int byteLen = this.source.parseInteger();
332
333         CharBuffer encoded =
334                 this.decoderUTF16LE.parseString(this.source, byteLen);
335
336         String result = encoded.toString();
337
338         return result;
339     }
340
341 }