ByteTokenStream.java
package org.argouml.language.java.reveng.classfile;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.antlr.runtime.Token;
import org.antlr.runtime.TokenSource;
import org.antlr.runtime.TokenStream;
/**
* A byte token stream that completely loads a specified amount of data from an
* InputStream instance into memory (byte array) at once.
*
* For simplicity, ANTLRStringStream was reused, which uses a char array. For
* using a byte array, a lot of stuff need to be coded.
*
* @author Thomas Neustupny <thn@tigris.org>
*/
public class ByteTokenStream implements TokenStream {
/** The data being scanned */
private byte[] data;
/** 0..n-1 index into data of next byte */
private int p = 0;
/** tracks how deep mark() calls are nested */
private int markDepth = 0;
/**
* A list of Integer objects that tracks the stream state value p that can
* change as you move through the byte stream. Indexed from 1..markDepth. A
* null is kept at index 0. Create upon first call to mark().
*/
private List<Integer> markers;
/** Track the last mark() call result value for use in rewind(). */
private int lastMarker;
/** What is name or source of this char stream? */
public String name;
/**
* Constructor. Loads all data from the input stream to an array.
*
* @param is the input stream
* @param size the amount of bytes to read
*/
public ByteTokenStream(InputStream is, int size) {
if (is != null && size > 0) {
data = new byte[size];
BufferedInputStream bis = new BufferedInputStream(is);
try {
bis.read(data);
} catch (IOException e) {
// TODO: add something here
}
name = is.toString();
}
}
public int LA(int i) {
if (i == 0) {
return 0; // undefined
}
if (i < 0) {
i++; // e.g., translate LA(-1) to use offset i=0; then
// data[p+0-1]
if ((p + i - 1) < 0) {
//return ByteToken.EOF; // invalid; no byte before first byte
}
}
if ((p + i - 1) >= data.length) {
//return ByteToken.EOF;
}
// this is tricky: bytes match with the token type that has a value of
// 4 higher than the byte value, so we add 4:
return (data[p + i - 1] & 0xff) + 4;
}
public void consume() {
// trivial because each byte is a token
if (p < data.length) {
p++;
}
}
public String getSourceName() {
return name;
}
public int index() {
return p;
}
public int mark() {
if (markers == null) {
markers = new ArrayList<Integer>();
markers.add(null); // depth 0 means no backtracking, leave blank
}
markDepth++;
Integer state = null;
if (markDepth >= markers.size()) {
state = new Integer(p);
markers.add(state);
} else {
state = markers.get(markDepth);
}
lastMarker = markDepth;
return markDepth;
}
public void release(int marker) {
// unwind any other markers made after m and release m
markDepth = marker;
// release this marker
markDepth--;
}
public void rewind() {
rewind(lastMarker);
}
public void rewind(int m) {
Integer state = markers.get(m);
// restore stream state
seek(state.intValue());
release(m);
}
public void seek(int index) {
// just jump, trivial because each byte is a token
// otherwise, a sequence of consume() call might be needed
p = index;
}
public int size() {
return data.length;
}
public Token LT(int i) {
return null; //new ByteToken((byte) LA(i));
}
public Token get(int i) {
return null; //new ByteToken(data[i - 1]);
}
public TokenSource getTokenSource() {
// not needed in the parser
return null;
}
public String toString(int arg0, int arg1) {
// not needed in the parser
return null;
}
public String toString(Token arg0, Token arg1) {
// not needed in the parser
return null;
}
}