OSDN Git Service

Merge develop into pomconfig
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / bin / 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.sfjp.mikutoga.bin.parser;
9
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;
19
20 /**
21  * 入力ストリームをソースとするバイナリパーサ実装。
22  */
23 public class CommonParser implements BinParser{
24
25     private static final String ERRMSG_ILLENC =
26             "illegal character encoding";
27     private static final String ERRMSG_UNMAP =
28             "unmapped character";
29
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;
34
35     private static final int MASK_8BIT  =   0xff;
36     private static final int MASK_16BIT = 0xffff;
37
38     static{
39         assert BYTES_PRIM >= BYTES_FLOAT;
40         assert BYTES_PRIM >= BYTES_INT;
41         assert BYTES_PRIM >= BYTES_SHORT;
42     }
43
44
45     private final PushbackInputStream is;
46
47     private final byte[] readBuffer;
48 //  private final ByteBuffer beBuf;
49     private final ByteBuffer leBuf;
50
51     private long position = 0L;
52
53     private ByteBuffer btextBuf;
54
55
56     /**
57      * コンストラクタ。
58      * @param source 入力ソース
59      */
60     public CommonParser(InputStream source){
61         super();
62
63         this.is = new PushbackInputStream(source, 1);
64
65         this.readBuffer = new byte[BYTES_PRIM];
66
67 //      this.beBuf = ByteBuffer.wrap(this.readBuffer);
68         this.leBuf = ByteBuffer.wrap(this.readBuffer);
69
70 //      this.beBuf.order(ByteOrder.BIG_ENDIAN);
71         this.leBuf.order(ByteOrder.LITTLE_ENDIAN);
72
73         return;
74     }
75
76
77     /**
78      * {@inheritDoc}
79      * @return {@inheritDoc}
80      */
81     @Override
82     public long getPosition(){
83         long result = this.position;
84         return result;
85     }
86
87     /**
88      * {@inheritDoc}
89      * @return {@inheritDoc}
90      * @throws IOException {@inheritDoc}
91      */
92     @Override
93     public boolean hasMore() throws IOException{
94         int bVal;
95
96         try{
97             bVal = this.is.read();
98         }catch(EOFException e){ // ありえない?
99             return false;
100         }
101
102         if(bVal < 0){
103             return false;
104         }
105
106         this.is.unread(bVal);
107
108         return true;
109     }
110
111     /**
112      * {@inheritDoc}
113      * @param skipLength {@inheritDoc}
114      * @throws IOException {@inheritDoc}
115      * @throws MmdEofException {@inheritDoc}
116      */
117     @Override
118     public void skip(long skipLength)
119             throws IOException, MmdEofException {
120         long remain = skipLength;
121
122         while(remain > 0L){
123             long txSize = this.is.skip(remain);
124             if(txSize <= 0L){
125                 throw new MmdEofException(this.position);
126             }
127             remain -= txSize;
128             this.position += txSize;
129         }
130
131         return;
132     }
133
134     /**
135      * {@inheritDoc}
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}
143      */
144     @Override
145     public void parseByteArray(byte[] dst, int off, int length)
146             throws NullPointerException,
147                    IndexOutOfBoundsException,
148                    IOException,
149                    MmdEofException {
150         int remain = length;
151         int offset = off;
152
153         while(remain > 0){
154             int txSize = this.is.read(dst, offset, remain);
155             if(txSize <= 0){
156                 throw new MmdEofException(this.position);
157             }
158             remain -= txSize;
159             offset += txSize;
160             this.position += txSize;
161         }
162
163         return;
164     }
165
166     /**
167      * {@inheritDoc}
168      * @param dst {@inheritDoc}
169      * @throws NullPointerException {@inheritDoc}
170      * @throws IOException {@inheritDoc}
171      * @throws MmdEofException {@inheritDoc}
172      */
173     @Override
174     public void parseByteArray(byte[] dst)
175             throws NullPointerException, IOException, MmdEofException{
176         parseByteArray(dst, 0, dst.length);
177         return;
178     }
179
180     /**
181      * 内部バッファへ指定バイト数だけ読み込む。
182      * @param fillSize バイト長
183      * @throws IOException IOエラー
184      * @throws MmdEofException 読み込む途中でストリーム終端に達した。
185      */
186     private void fillBuffer(int fillSize)
187             throws IOException, MmdEofException {
188         parseByteArray(this.readBuffer, 0, fillSize);
189         return;
190     }
191
192     /**
193      * {@inheritDoc}
194      * @return {@inheritDoc}
195      * @throws IOException {@inheritDoc}
196      * @throws MmdEofException {@inheritDoc}
197      */
198     @Override
199     public byte parseByte()
200             throws IOException, MmdEofException{
201         int bData = this.is.read();
202         if(bData < 0){
203             throw new MmdEofException(this.position);
204         }
205
206         byte result = (byte) bData;
207         this.position++;
208
209         return result;
210     }
211
212     /**
213      * {@inheritDoc}
214      * @return {@inheritDoc}
215      * @throws IOException {@inheritDoc}
216      * @throws MmdEofException {@inheritDoc}
217      */
218     @Override
219     public int parseUByteAsInt()
220             throws IOException, MmdEofException{
221         return parseByte() & MASK_8BIT;
222     }
223
224     /**
225      * {@inheritDoc}
226      * @return {@inheritDoc}
227      * @throws IOException {@inheritDoc}
228      * @throws MmdEofException {@inheritDoc}
229      */
230     @Override
231     public boolean parseBoolean()
232             throws IOException, MmdEofException{
233         byte result = parseByte();
234         if(result == 0x00) return false;
235         return true;
236     }
237
238     /**
239      * {@inheritDoc}
240      * @return {@inheritDoc}
241      * @throws IOException {@inheritDoc}
242      * @throws MmdEofException {@inheritDoc}
243      */
244     @Override
245     public short parseLeShort()
246             throws IOException, MmdEofException{
247         fillBuffer(BYTES_SHORT);
248         short result = this.leBuf.getShort(0);
249         return result;
250     }
251
252     /**
253      * {@inheritDoc}
254      * @return {@inheritDoc}
255      * @throws IOException {@inheritDoc}
256      * @throws MmdEofException {@inheritDoc}
257      */
258     @Override
259     public int parseLeUShortAsInt()
260             throws IOException, MmdEofException{
261         return parseLeShort() & MASK_16BIT;
262     }
263
264     /**
265      * {@inheritDoc}
266      * @return {@inheritDoc}
267      * @throws IOException {@inheritDoc}
268      * @throws MmdEofException {@inheritDoc}
269      */
270     @Override
271     public int parseLeInt()
272             throws IOException, MmdEofException{
273         fillBuffer(BYTES_INT);
274         int result = this.leBuf.getInt(0);
275         return result;
276     }
277
278     /**
279      * {@inheritDoc}
280      * @return {@inheritDoc}
281      * @throws IOException {@inheritDoc}
282      * @throws MmdEofException {@inheritDoc}
283      */
284     @Override
285     public float parseLeFloat()
286             throws IOException, MmdEofException{
287         fillBuffer(BYTES_FLOAT);
288         float result = this.leBuf.getFloat(0);
289         return result;
290     }
291
292     /**
293      * {@inheritDoc}
294      * @param decoder {@inheritDoc}
295      * @param byteLen {@inheritDoc}
296      * @return {@inheritDoc}
297      * @throws IOException {@inheritDoc}
298      * @throws MmdEofException {@inheritDoc}
299      * @throws MmdFormatException {@inheritDoc}
300      */
301     @Override
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);
306         }
307
308         byte[] buf = this.btextBuf.array();
309         this.btextBuf.clear();
310         parseByteArray(buf, 0, byteLen);
311         this.btextBuf.limit(byteLen);
312
313         String result;
314
315         try{
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);
321             ex.initCause(e);
322             throw ex;
323         }catch(MalformedInputException e){
324             String errmsg = ERRMSG_ILLENC;
325             long errpos = getPosition() - byteLen + e.getInputLength();
326             MmdFormatException ex = new MmdFormatException(errmsg, errpos);
327             ex.initCause(e);
328             throw ex;
329         }catch(CharacterCodingException e){  // 状況不明
330             String errmsg = ERRMSG_ILLENC;
331             long errpos = getPosition();
332             MmdFormatException ex = new MmdFormatException(errmsg, errpos);
333             ex.initCause(e);
334             throw ex;
335         }
336
337         return result;
338     }
339
340 }