4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sourceforge.mikutoga.parser;
10 import java.io.IOException;
11 import java.nio.CharBuffer;
12 import java.nio.charset.Charset;
17 public class CommonParser {
20 * PMDで用いられる文字エンコーディング(windows-31j)。
21 * ほぼShift_JISのスーパーセットと思ってよい。
22 * デコード結果はUCS-2集合に収まるはず。
24 public static final Charset CS_WIN31J = Charset.forName("windows-31j");
26 /** PMXで用いられる文字エンコーディング(UTF-8)。 */
27 public static final Charset CS_UTF8 = Charset.forName("UTF-8");
29 /** PMXで用いられる文字エンコーディング(UTF-16のリトルエンディアン)。 */
30 public static final Charset CS_UTF16LE = Charset.forName("UTF-16LE");
32 private static final int MASK_8BIT = 0xff;
33 private static final int MASK_16BIT = 0xffff;
36 private final MmdInputStream is;
38 private final TextDecoder decoderWin31j = new TextDecoder(CS_WIN31J);
39 private final TextDecoder decoderUTF8 = new TextDecoder(CS_UTF8);
40 private final TextDecoder decoderUTF16LE = new TextDecoder(CS_UTF16LE);
46 public CommonParser(MmdInputStream source){
51 this.decoderWin31j .setZeroChopMode(true);
52 this.decoderUTF8 .setZeroChopMode(false);
53 this.decoderUTF16LE.setZeroChopMode(false);
62 protected MmdInputStream getSource(){
68 * @return 入力ソースの読み込み位置。単位はbyte。
70 protected long getPosition(){
71 long result = this.is.getPosition();
76 * 入力ソースにまだデータが残っているか判定する。
77 * @return まだ読み込んでいないデータが残っていればtrue
78 * @throws IOException IOエラー
79 * @see MmdInputStream#hasMore()
81 protected boolean hasMore() throws IOException{
82 boolean result = this.is.hasMore();
88 * @param skipLength 読み飛ばすバイト数。
89 * @throws IOException IOエラー
90 * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。
91 * @see MmdInputStream#skip(long)
93 protected void skip(long skipLength)
94 throws IOException, MmdEofException {
95 long result = this.is.skipRepeat(skipLength);
96 if(result != skipLength){
97 throw new MmdEofException(this.is.getPosition());
105 * @param skipLength 読み飛ばすバイト数。
106 * @throws IOException IOエラー
107 * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。
108 * @see MmdInputStream#skip(long)
110 protected void skip(int skipLength)
111 throws IOException, MmdEofException {
112 skip((long) skipLength);
118 * @throws IOException IOエラー
119 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
120 * @see MmdInputStream#parseByte()
122 protected byte parseByte()
123 throws IOException, MmdEofException{
124 return this.is.parseByte();
128 * 符号無し値としてbyte値を読み込み、int型に変換して返す。
129 * 符号は拡張されない。(0xffは0x000000ffとなる)
130 * @return 読み込まれた値のint値
131 * @throws IOException IOエラー
132 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
133 * @see MmdInputStream#parseUByteAsInt()
135 protected int parseUByteAsInt()
136 throws IOException, MmdEofException{
137 return ((int) parseByte()) & MASK_8BIT;
141 * byte値を読み込み、boolean型に変換して返す。
142 * 0x00は偽、それ以外は真と解釈される。
143 * @return 読み込まれた値のboolean値
144 * @throws IOException IOエラー
145 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
146 * @see MmdInputStream#parseBoolean()
148 protected boolean parseBoolean()
149 throws IOException, MmdEofException{
150 return this.is.parseBoolean();
155 * short値はリトルエンディアンで格納されていると仮定される。
156 * @return 読み込んだshort値
157 * @throws IOException IOエラー
158 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
159 * @see MmdInputStream#parseShort()
161 protected short parseLeShort()
162 throws IOException, MmdEofException{
163 return this.is.parseLeShort();
167 * 符号無し値としてshort値を読み込み、int型に変換して返す。
168 * 符号は拡張されない。(0xffffは0x0000ffffとなる)
169 * short値はリトルエンディアンで格納されていると仮定される。
170 * @return 読み込まれた値のint値
171 * @throws IOException IOエラー
172 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
173 * @see MmdInputStream#parseUShortAsInteger()
175 protected int parseLeUShortAsInt()
176 throws IOException, MmdEofException{
177 return ((int) parseLeShort()) & MASK_16BIT;
182 * int値はリトルエンディアンで格納されていると仮定される。
184 * @throws IOException IOエラー
185 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
186 * @see MmdInputStream#parseInteger()
188 protected int parseLeInt()
189 throws IOException, MmdEofException{
190 return this.is.parseLeInt();
195 * float値はリトルエンディアンで格納されていると仮定される。
196 * @return 読み込んだfloat値
197 * @throws IOException IOエラー
198 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
199 * @see MmdInputStream#parseFloat()
201 protected float parseLeFloat()
202 throws IOException, MmdEofException{
203 return this.is.parseLeFloat();
209 * @param offset 読み込み開始オフセット
210 * @param length 読み込みバイト数
211 * @throws IOException IOエラー
212 * @throws NullPointerException 配列がnull
213 * @throws IndexOutOfBoundsException 引数が配列属性と矛盾
214 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
215 * @see MmdInputStream#parseByteArray(byte[], int, int)
217 protected void parseByteArray(byte[] dst, int offset, int length)
219 NullPointerException,
220 IndexOutOfBoundsException,
222 int readSize = this.is.read(dst, offset, length);
223 if(readSize != length){
224 throw new MmdEofException(this.is.getPosition());
234 * @throws IOException IOエラー
235 * @throws NullPointerException 配列がnull
236 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
237 * @see MmdInputStream#parseByteArray(byte[])
239 protected void parseByteArray(byte[] dst)
240 throws IOException, NullPointerException, MmdEofException{
241 parseByteArray(dst, 0, dst.length);
246 * 指定された最大バイト長に収まるゼロ終端(0x00)文字列を読み込む。
247 * 入力バイト列はwindows-31jエンコーディングとして解釈される。
249 * IO入力は指定バイト数だけ読み進められる。
250 * ゼロ終端が見つからないまま指定バイト数が読み込み終わった場合、
251 * そこまでのデータから文字列を構成する。
252 * @param maxlen 読み込みバイト数
254 * @throws IOException IOエラー
255 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
256 * @throws MmdFormatException 不正な文字エンコーディングが検出された。
258 protected String parseZeroTermWin31J(int maxlen)
263 this.decoderWin31j.parseString(this.is, maxlen);
265 String result = encoded.toString();
271 * 4byte整数によるバイト列長とそれに続くUTF8バイト列を
273 * @return デコードされた文字列。
274 * @throws IOException IOエラー
275 * @throws MmdEofException 予期せぬ入力終端
276 * @throws MmdFormatException 不正な文字エンコーディングが検出された。
278 protected String parseHollerithUtf8()
282 int byteLen = this.is.parseLeInt();
285 this.decoderUTF8.parseString(this.is, byteLen);
287 String result = encoded.toString();
293 * 4byte整数によるバイト列長とそれに続くUTF16-LEバイト列を
295 * @return デコードされた文字列。
296 * @throws IOException IOエラー
297 * @throws MmdEofException 予期せぬ入力終端
298 * @throws MmdFormatException 不正な文字エンコーディングが検出された。
300 protected String parseHollerithUtf16LE()
304 int byteLen = this.is.parseLeInt();
307 this.decoderUTF16LE.parseString(this.is, byteLen);
309 String result = encoded.toString();