2009-06-07 15:40:49 +02:00
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.EOFException;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.util.Stack;
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/**
|
|
|
|
* Utility class for reading raw data from a file.
|
|
|
|
* Does not extend InputStream, but does implement most of its methods.
|
|
|
|
*/
|
2009-06-07 15:40:49 +02:00
|
|
|
public class HexInputStream {
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/** The InputStream this stream is based on. */
|
2009-06-07 15:40:49 +02:00
|
|
|
private volatile InputStream dis;
|
2010-09-22 20:09:32 +02:00
|
|
|
/** The current position of this stream. */
|
2009-06-07 15:40:49 +02:00
|
|
|
private volatile long currPos;
|
2010-09-22 20:09:32 +02:00
|
|
|
/** Get the current position of this stream. */
|
2009-06-07 15:40:49 +02:00
|
|
|
public long getPosition(){ return this.currPos; }
|
2010-09-22 20:09:32 +02:00
|
|
|
/**
|
|
|
|
* Sets the position of this stream.
|
|
|
|
* @param newPos The desired position of the stream.
|
|
|
|
* @throws IOException when the given position cannot be reached
|
|
|
|
*/
|
2009-06-07 15:40:49 +02:00
|
|
|
public void setPosition(long newPos) throws IOException{ this.skip(newPos - currPos); }
|
2010-09-22 20:09:32 +02:00
|
|
|
/** Convenience method for {@link #setPosition(long)}. */
|
2009-06-07 15:40:49 +02:00
|
|
|
public void goTo(long pos) throws IOException{ this.setPosition(pos); }
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/** The stack of saved positions for this stream. */
|
2009-06-07 15:40:49 +02:00
|
|
|
private Stack<Long> positionStack;
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/**
|
|
|
|
* Creates a new HexInputStream, based off another InputStream.
|
|
|
|
* The 0-position of the new stream is the current position of the
|
|
|
|
* given stream.
|
|
|
|
* @param baseInputStream The InputStream to base the new HexInputStream on.
|
|
|
|
*/
|
2009-06-07 15:40:49 +02:00
|
|
|
public HexInputStream(InputStream baseInputStream) {
|
|
|
|
this.dis = baseInputStream;
|
|
|
|
this.currPos = 0;
|
|
|
|
this.positionStack = new Stack<Long>();
|
|
|
|
}
|
2010-09-22 20:09:32 +02:00
|
|
|
/**
|
|
|
|
* Creates a new HexInputStream for reading a file.
|
|
|
|
* @param String The name of the file to read.
|
|
|
|
* @throws FileNotFoundException If the given file does not exist.
|
|
|
|
*/
|
2009-06-07 15:40:49 +02:00
|
|
|
public HexInputStream(String filename) throws FileNotFoundException {
|
|
|
|
this.dis = new DataInputStream(new FileInputStream(new File(filename)));
|
|
|
|
this.currPos = 0;
|
|
|
|
this.positionStack = new Stack<Long>();
|
|
|
|
}
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/**
|
|
|
|
* Returns an estimate of the number of bytes left to read until the EOF.
|
|
|
|
* See {@link InputStream#available}
|
|
|
|
*/
|
2009-06-07 15:40:49 +02:00
|
|
|
public int available() throws IOException{
|
|
|
|
return dis.available();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read the next byte from a file. If the EOF has been reached, -1 is returned */
|
|
|
|
public int read() throws IOException{
|
|
|
|
int b = dis.read();
|
|
|
|
if(b != -1)
|
|
|
|
currPos++;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read an array of bytes from this stream */
|
|
|
|
public int[] readBytes(int length) throws IOException{
|
|
|
|
int[] data = new int[length];
|
|
|
|
for(int i=0; i<length; i++)
|
|
|
|
data[i] = readU8();
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a byte from this stream */
|
|
|
|
public int readU8() throws IOException {
|
|
|
|
int b = dis.read();
|
|
|
|
currPos++;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a BigEndian s16 from this stream */
|
|
|
|
public short readS16() throws IOException {
|
|
|
|
short word = 0;
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
word = (short)(word | (readU8() << (8 * i)));
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a LittleEndian s16 from this stream */
|
|
|
|
public short readlS16() throws IOException {
|
|
|
|
short word = 0;
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
word = (short)((word << 8) | readU8());
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a BigEndian u16 from this stream */
|
|
|
|
public int readU16() throws IOException {
|
|
|
|
int word = 0;
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
word = word | (readU8() << (8 * i));
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a LittleEndian u16 from this stream */
|
|
|
|
public int readlU16() throws IOException {
|
|
|
|
int word = 0;
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
word = (word << 8) | readU8();
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a BigEndian s32 from this stream (a signed int) */
|
|
|
|
public int readS32() throws IOException {
|
|
|
|
int dword = 0;
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
dword = dword | (readU8() << (8 * i));
|
|
|
|
return dword;
|
|
|
|
}
|
|
|
|
/** Read a LittleEndian s32 from this stream (a signed int) */
|
|
|
|
public int readlS32() throws IOException {
|
|
|
|
int dword = 0;
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
dword = (dword << 8) | readU8();
|
|
|
|
return dword;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Read a BigEndian u32 from this stream (an unsigned int) */
|
|
|
|
public long readU32() throws IOException {
|
|
|
|
long dword = 0;
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
dword = dword | (readU8() << (8 * i));
|
|
|
|
|
|
|
|
return dword;
|
|
|
|
}
|
|
|
|
/** Read a LittleEndian u32 from this stream (an unsigned int) */
|
|
|
|
public long readlU32() throws IOException {
|
|
|
|
long dword = 0;
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
dword = (dword << 8) | readU8();
|
|
|
|
return dword;
|
|
|
|
}
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/** Read a BigEndian s64 from this stream (a signed int) */
|
2009-06-07 15:40:49 +02:00
|
|
|
public long readS64() throws IOException {
|
|
|
|
long qword = 0;
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
|
|
qword = qword | (readU8() << (8 * i));
|
|
|
|
return qword;
|
|
|
|
}
|
2010-09-22 20:09:32 +02:00
|
|
|
/** Read a LittleEndian s64 from this stream (a signed int) */
|
2009-06-07 15:40:49 +02:00
|
|
|
public long readlS64() throws IOException {
|
|
|
|
long qword = 0;
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
|
|
qword = (qword << 8) | readU8();
|
|
|
|
return qword;
|
|
|
|
}
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
// an u64 fits into a BigInt, but I prefer not to return those for read-methods.
|
2009-06-07 15:40:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
/** Peek at the next u8 from this stream */
|
|
|
|
public short peekU8() throws IOException{
|
|
|
|
try{
|
|
|
|
short b = (short)readU8();
|
|
|
|
skip(-1);
|
|
|
|
return b;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next s16 from this stream */
|
|
|
|
public short peekS16() throws IOException{
|
|
|
|
try{
|
|
|
|
short s = readS16();
|
|
|
|
skip(-2);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next little-endian s16 from this stream */
|
|
|
|
public short peeklS16() throws IOException{
|
|
|
|
try{
|
|
|
|
short s = readlS16();
|
|
|
|
skip(-2);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next u16 from this stream */
|
|
|
|
public int peekU16() throws IOException{
|
|
|
|
try{
|
|
|
|
int s = readU16();
|
|
|
|
skip(-2);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next little-endian u16 from this stream */
|
|
|
|
public int peeklU16() throws IOException{
|
|
|
|
try{
|
|
|
|
int s = readlU16();
|
|
|
|
skip(-2);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next s32 from this stream */
|
|
|
|
public int peekS32() throws IOException{
|
|
|
|
try{
|
|
|
|
int s = readS32();
|
|
|
|
skip(-4);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next little-endian s32 from this stream */
|
|
|
|
public int peeklS32() throws IOException{
|
|
|
|
try{
|
|
|
|
int s = readlS32();
|
|
|
|
skip(-4);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next u32 from this stream */
|
|
|
|
public long peekU32() throws IOException{
|
|
|
|
try{
|
|
|
|
long s = readU32();
|
|
|
|
skip(-4);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next little-endian u32 from this stream */
|
|
|
|
public long peeklU32() throws IOException{
|
|
|
|
try{
|
|
|
|
long s = readlU32();
|
|
|
|
skip(-4);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next s64 from this stream */
|
|
|
|
public long peekS64() throws IOException{
|
|
|
|
try{
|
|
|
|
long s = readS64();
|
|
|
|
skip(-8);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
/** peek at the next little-endian s64 from this stream */
|
|
|
|
public long peeklS64() throws IOException{
|
|
|
|
try{
|
|
|
|
long s = readlS64();
|
|
|
|
skip(-8);
|
|
|
|
return s;
|
|
|
|
} catch (EOFException ex){ return -1; }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Read a String of a certain length from this stream */
|
|
|
|
public String readString(int length) throws IOException{
|
|
|
|
StringBuffer sbuf = new StringBuffer(length);
|
|
|
|
for(int i=0; i<length; i++)
|
|
|
|
sbuf.append((char)readU8());
|
|
|
|
return sbuf.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads a \0-terminated string from this stream
|
2010-09-22 20:09:32 +02:00
|
|
|
* @param totlength the total length of the string in the data. If -1, read until a \0 is read.
|
2009-06-07 15:40:49 +02:00
|
|
|
*/
|
|
|
|
public String read0TerminatedString(int totlength) throws IOException{
|
|
|
|
if(totlength == -1){
|
|
|
|
StringBuffer sbuf = new StringBuffer();
|
|
|
|
while(peekU8() != 0)
|
|
|
|
sbuf.append((char)readU8());
|
|
|
|
readU8(); // read the 0 as well
|
|
|
|
return sbuf.toString();
|
|
|
|
} else {
|
|
|
|
StringBuffer sbuf = new StringBuffer();
|
|
|
|
boolean read0 = false;
|
|
|
|
for(int i=0; i<totlength; i++){
|
|
|
|
if(peekU8() == 0)
|
|
|
|
read0 = true;
|
|
|
|
char c = (char)readU8();
|
|
|
|
if(!read0)
|
|
|
|
sbuf.append(c);
|
|
|
|
}
|
|
|
|
return sbuf.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Close this stream */
|
|
|
|
public void close() throws IOException{
|
|
|
|
dis.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Skip n bytes */
|
|
|
|
public void skip(long n) throws IOException{
|
2010-09-22 20:09:32 +02:00
|
|
|
currPos += dis.skip(n);
|
2009-06-07 15:40:49 +02:00
|
|
|
}
|
|
|
|
|
2010-09-22 20:09:32 +02:00
|
|
|
/** Reset this stream to its base position. */
|
2009-06-07 15:40:49 +02:00
|
|
|
public void reset() throws IOException{
|
|
|
|
this.goTo(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Save the current position on the local stack */
|
|
|
|
public void savePosition(){
|
|
|
|
this.positionStack.push(this.currPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Pop the last saved position from the local stack and restore that position */
|
|
|
|
public void loadPosition() throws IOException{
|
|
|
|
if(!this.positionStack.isEmpty()){
|
|
|
|
long pos = this.positionStack.peek();
|
|
|
|
this.positionStack.pop();
|
|
|
|
this.goTo(pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|