4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sourceforge.mikutoga.parser;
10 import java.io.EOFException;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.PushbackInputStream;
14 import java.nio.ByteBuffer;
15 import java.nio.ByteOrder;
20 public class CommonParser {
22 private static final int BYTES_SHORT = Short .SIZE / Byte.SIZE;
23 private static final int BYTES_INT = Integer.SIZE / Byte.SIZE;
24 private static final int BYTES_FLOAT = Float .SIZE / Byte.SIZE;
25 private static final int BYTES_PRIM = 4;
27 private static final int MASK_8BIT = 0xff;
28 private static final int MASK_16BIT = 0xffff;
31 assert BYTES_PRIM >= BYTES_FLOAT;
32 assert BYTES_PRIM >= BYTES_INT;
33 assert BYTES_PRIM >= BYTES_SHORT;
37 private final PushbackInputStream is;
39 private final byte[] readBuffer;
40 private final ByteBuffer beBuf;
41 private final ByteBuffer leBuf;
43 private long position = 0L;
50 public CommonParser(InputStream source){
53 this.is = new PushbackInputStream(source, 1);
55 this.readBuffer = new byte[BYTES_PRIM];
57 this.beBuf = ByteBuffer.wrap(this.readBuffer);
58 this.leBuf = ByteBuffer.wrap(this.readBuffer);
60 this.beBuf.order(ByteOrder.BIG_ENDIAN);
61 this.leBuf.order(ByteOrder.LITTLE_ENDIAN);
69 * @return 入力ソースの読み込み位置。単位はbyte。
71 protected long getPosition(){
72 long result = this.position;
77 * 入力ソースにまだデータが残っているか判定する。
78 * @return まだ読み込んでいないデータが残っていればtrue
79 * @throws IOException IOエラー
81 public boolean hasMore() throws IOException{
85 bVal = this.is.read();
86 }catch(EOFException e){ // ありえない?
101 * @param skipLength 読み飛ばすバイト数。
102 * @throws IOException IOエラー
103 * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。
104 * @see InputStream#skip(long)
106 protected void skip(long skipLength)
107 throws IOException, MmdEofException {
108 long remain = skipLength;
111 long txSize = this.is.skip(remain);
113 throw new MmdEofException(this.position);
116 this.position += txSize;
125 * @param off 読み込み開始オフセット
126 * @param length 読み込みバイト数
127 * @throws IOException IOエラー
128 * @throws NullPointerException 配列がnull
129 * @throws IndexOutOfBoundsException 引数が配列属性と矛盾
130 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
131 * @see InputStream#read(byte[], int, int)
133 protected void parseByteArray(byte[] dst, int off, int length)
135 NullPointerException,
136 IndexOutOfBoundsException,
142 int txSize = this.is.read(dst, offset, remain);
144 throw new MmdEofException(this.position);
148 this.position += txSize;
158 * @throws IOException IOエラー
159 * @throws NullPointerException 配列がnull
160 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
161 * @see InputStream#read(byte[])
163 protected void parseByteArray(byte[] dst)
164 throws IOException, NullPointerException, MmdEofException{
165 parseByteArray(dst, 0, dst.length);
170 * 内部バッファへ指定バイト数だけ読み込む。
172 * @throws IOException
173 * @throws MmdEofException
175 private void fillBuffer(int fillSize)
176 throws IOException, MmdEofException {
177 parseByteArray(this.readBuffer, 0, fillSize);
184 * @throws IOException IOエラー
185 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
187 protected byte parseByte()
188 throws IOException, MmdEofException{
189 int bData = this.is.read();
191 throw new MmdEofException(this.position);
194 byte result = (byte) bData;
201 * 符号無し値としてbyte値を読み込み、int型に変換して返す。
202 * 符号は拡張されない。(0xffは0x000000ffとなる)
203 * @return 読み込まれた値のint値
204 * @throws IOException IOエラー
205 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
207 protected int parseUByteAsInt()
208 throws IOException, MmdEofException{
209 return ((int) parseByte()) & MASK_8BIT;
213 * byte値を読み込み、boolean型に変換して返す。
214 * 0x00は偽、それ以外は真と解釈される。
215 * @return 読み込まれた値のboolean値
216 * @throws IOException IOエラー
217 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
219 protected boolean parseBoolean()
220 throws IOException, MmdEofException{
221 byte result = parseByte();
222 if(result == 0x00) return false;
228 * short値はリトルエンディアンで格納されていると仮定される。
229 * @return 読み込んだshort値
230 * @throws IOException IOエラー
231 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
233 protected short parseLeShort()
234 throws IOException, MmdEofException{
235 fillBuffer(BYTES_SHORT);
236 short result = this.leBuf.getShort(0);
241 * 符号無し値としてshort値を読み込み、int型に変換して返す。
242 * 符号は拡張されない。(0xffffは0x0000ffffとなる)
243 * short値はリトルエンディアンで格納されていると仮定される。
244 * @return 読み込まれた値のint値
245 * @throws IOException IOエラー
246 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
248 protected int parseLeUShortAsInt()
249 throws IOException, MmdEofException{
250 return ((int) parseLeShort()) & MASK_16BIT;
255 * int値はリトルエンディアンで格納されていると仮定される。
257 * @throws IOException IOエラー
258 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
260 protected int parseLeInt()
261 throws IOException, MmdEofException{
262 fillBuffer(BYTES_INT);
263 int result = this.leBuf.getInt(0);
269 * float値はリトルエンディアンで格納されていると仮定される。
270 * @return 読み込んだfloat値
271 * @throws IOException IOエラー
272 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
274 protected float parseLeFloat()
275 throws IOException, MmdEofException{
276 fillBuffer(BYTES_FLOAT);
277 float result = this.leBuf.getFloat(0);
283 * @param decoder 文字デコーダ
284 * @param byteLen 読み込む固定バイト長
286 * @throws IOException 入力エラー
287 * @throws MmdEofException 固定長バイト列を読む前に末端に達した。
288 * @throws MmdFormatException 文字エンコーディングに関するエラー
290 protected String parseString(TextDecoder decoder, int byteLen)
291 throws IOException, MmdEofException, MmdFormatException {
292 byte[] buf = decoder.prepareBuffer(byteLen);
293 parseByteArray(buf, 0, byteLen);
294 long basePos = getPosition();
295 String result= decoder.decode(basePos, byteLen);