4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sfjp.mikutoga.bin.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;
16 import java.nio.charset.CharacterCodingException;
17 import java.nio.charset.MalformedInputException;
18 import java.nio.charset.UnmappableCharacterException;
21 * 入力ストリームをソースとするバイナリパーサ実装。
23 public class CommonParser implements BinParser{
25 private static final String ERRMSG_ILLENC =
26 "illegal character encoding";
27 private static final String ERRMSG_UNMAP =
30 private static final int BYTES_SHORT = Short .SIZE / Byte.SIZE;
31 private static final int BYTES_INT = Integer.SIZE / Byte.SIZE;
32 private static final int BYTES_FLOAT = Float .SIZE / Byte.SIZE;
33 private static final int BYTES_PRIM = 4;
35 private static final int MASK_8BIT = 0xff;
36 private static final int MASK_16BIT = 0xffff;
39 assert BYTES_PRIM >= BYTES_FLOAT;
40 assert BYTES_PRIM >= BYTES_INT;
41 assert BYTES_PRIM >= BYTES_SHORT;
45 private final PushbackInputStream is;
47 private final byte[] readBuffer;
48 // private final ByteBuffer beBuf;
49 private final ByteBuffer leBuf;
51 private long position = 0L;
53 private ByteBuffer btextBuf;
60 public CommonParser(InputStream source){
63 this.is = new PushbackInputStream(source, 1);
65 this.readBuffer = new byte[BYTES_PRIM];
67 // this.beBuf = ByteBuffer.wrap(this.readBuffer);
68 this.leBuf = ByteBuffer.wrap(this.readBuffer);
70 // this.beBuf.order(ByteOrder.BIG_ENDIAN);
71 this.leBuf.order(ByteOrder.LITTLE_ENDIAN);
79 * @return {@inheritDoc}
82 public long getPosition(){
83 long result = this.position;
89 * @return {@inheritDoc}
90 * @throws IOException {@inheritDoc}
93 public boolean hasMore() throws IOException{
97 bVal = this.is.read();
98 }catch(EOFException e){ // ありえない?
106 this.is.unread(bVal);
113 * @param skipLength {@inheritDoc}
114 * @throws IOException {@inheritDoc}
115 * @throws MmdEofException {@inheritDoc}
118 public void skip(long skipLength)
119 throws IOException, MmdEofException {
120 long remain = skipLength;
123 long txSize = this.is.skip(remain);
125 throw new MmdEofException(this.position);
128 this.position += txSize;
136 * @param dst {@inheritDoc}
137 * @param off {@inheritDoc}
138 * @param length {@inheritDoc}
139 * @throws NullPointerException {@inheritDoc}
140 * @throws IndexOutOfBoundsException {@inheritDoc}
141 * @throws IOException {@inheritDoc}
142 * @throws MmdEofException {@inheritDoc}
145 public void parseByteArray(byte[] dst, int off, int length)
146 throws NullPointerException,
147 IndexOutOfBoundsException,
154 int txSize = this.is.read(dst, offset, remain);
156 throw new MmdEofException(this.position);
160 this.position += txSize;
168 * @param dst {@inheritDoc}
169 * @throws NullPointerException {@inheritDoc}
170 * @throws IOException {@inheritDoc}
171 * @throws MmdEofException {@inheritDoc}
174 public void parseByteArray(byte[] dst)
175 throws NullPointerException, IOException, MmdEofException{
176 parseByteArray(dst, 0, dst.length);
181 * 内部バッファへ指定バイト数だけ読み込む。
182 * @param fillSize バイト長
183 * @throws IOException IOエラー
184 * @throws MmdEofException 読み込む途中でストリーム終端に達した。
186 private void fillBuffer(int fillSize)
187 throws IOException, MmdEofException {
188 parseByteArray(this.readBuffer, 0, fillSize);
194 * @return {@inheritDoc}
195 * @throws IOException {@inheritDoc}
196 * @throws MmdEofException {@inheritDoc}
199 public byte parseByte()
200 throws IOException, MmdEofException{
201 int bData = this.is.read();
203 throw new MmdEofException(this.position);
206 byte result = (byte) bData;
214 * @return {@inheritDoc}
215 * @throws IOException {@inheritDoc}
216 * @throws MmdEofException {@inheritDoc}
219 public int parseUByteAsInt()
220 throws IOException, MmdEofException{
221 return parseByte() & MASK_8BIT;
226 * @return {@inheritDoc}
227 * @throws IOException {@inheritDoc}
228 * @throws MmdEofException {@inheritDoc}
231 public boolean parseBoolean()
232 throws IOException, MmdEofException{
233 byte result = parseByte();
234 if(result == 0x00) return false;
240 * @return {@inheritDoc}
241 * @throws IOException {@inheritDoc}
242 * @throws MmdEofException {@inheritDoc}
245 public short parseLeShort()
246 throws IOException, MmdEofException{
247 fillBuffer(BYTES_SHORT);
248 short result = this.leBuf.getShort(0);
254 * @return {@inheritDoc}
255 * @throws IOException {@inheritDoc}
256 * @throws MmdEofException {@inheritDoc}
259 public int parseLeUShortAsInt()
260 throws IOException, MmdEofException{
261 return parseLeShort() & MASK_16BIT;
266 * @return {@inheritDoc}
267 * @throws IOException {@inheritDoc}
268 * @throws MmdEofException {@inheritDoc}
271 public int parseLeInt()
272 throws IOException, MmdEofException{
273 fillBuffer(BYTES_INT);
274 int result = this.leBuf.getInt(0);
280 * @return {@inheritDoc}
281 * @throws IOException {@inheritDoc}
282 * @throws MmdEofException {@inheritDoc}
285 public float parseLeFloat()
286 throws IOException, MmdEofException{
287 fillBuffer(BYTES_FLOAT);
288 float result = this.leBuf.getFloat(0);
294 * @param decoder {@inheritDoc}
295 * @param byteLen {@inheritDoc}
296 * @return {@inheritDoc}
297 * @throws IOException {@inheritDoc}
298 * @throws MmdEofException {@inheritDoc}
299 * @throws MmdFormatException {@inheritDoc}
302 public String parseString(TextDecoder decoder, int byteLen)
303 throws IOException, MmdEofException, MmdFormatException {
304 if(this.btextBuf == null || this.btextBuf.capacity() < byteLen){
305 this.btextBuf = ByteBuffer.allocate(byteLen);
308 byte[] buf = this.btextBuf.array();
309 this.btextBuf.clear();
310 parseByteArray(buf, 0, byteLen);
311 this.btextBuf.limit(byteLen);
316 result = decoder.decode(this.btextBuf);
317 }catch(UnmappableCharacterException e){
318 String errmsg = ERRMSG_UNMAP;
319 long errpos = getPosition() - byteLen + e.getInputLength();
320 MmdFormatException ex = new MmdFormatException(errmsg, errpos);
323 }catch(MalformedInputException e){
324 String errmsg = ERRMSG_ILLENC;
325 long errpos = getPosition() - byteLen + e.getInputLength();
326 MmdFormatException ex = new MmdFormatException(errmsg, errpos);
329 }catch(CharacterCodingException e){ // 状況不明
330 String errmsg = ERRMSG_ILLENC;
331 long errpos = getPosition();
332 MmdFormatException ex = new MmdFormatException(errmsg, errpos);