package edu.ucla.nesl.mca.xdr;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A class for reading XDR files. Not too hard to do in Java since the XDR
* format is very similar to the Java native DataStream format, except for
* String and the fact that elements (or an array of elements) are always padded
* to a multiple of 4 bytes.
*
* This class requires the user to call the pad method, to skip to the next
* 4-byte boundary after reading an element or array of elements that may not
* span a multiple of 4 bytes.
*
* @author Tony Johnson (tonyj@slac.stanford.edu)
* @version $Id: XDRInputStream.java 13677 2009-10-20 03:33:02Z tonyj $
*/
public class XDRInputStream extends DataInputStream implements XDRDataInput {
private CountedInputStream cin;
private final static int SANITY_CHECK = Integer.getInteger(
"hep.io.xdr.sanityCheck", 100000).intValue();
public XDRInputStream(InputStream in) {
super(new CountedInputStream(in));
cin = (CountedInputStream) this.in;
}
public long getBytesRead() {
return cin.getBytesRead();
}
/**
* Sets a limit on the number of bytes that can be read from this file
* before an EOF will be generated
*/
public void setReadLimit(int bytes) {
cin.setReadLimit(bytes);
}
public void clearReadLimit() {
cin.clearReadLimit();
}
/**
* Skips appropriate amount to bring stream to 4-byte boundary.
*/
public void pad() throws IOException {
int offset = (int) (getBytesRead() % 4);
if (offset != 0)
skipBytes(4 - offset);
}
public double[] readDoubleArray(double[] buffer) throws IOException {
int l = readInt();
if (l > SANITY_CHECK)
throw new IOException("Array length failed sanity check: " + l);
double[] result = buffer;
if ((buffer == null) || (l > buffer.length))
result = new double[l];
for (int i = 0; i < l; i++)
result[i] = readDouble();
return result;
}
public float[] readFloatArray(float[] buffer) throws IOException {
int l = readInt();
if (l > SANITY_CHECK)
throw new IOException("Array length failed sanity check: " + l);
float[] result = buffer;
if ((buffer == null) || (l > buffer.length))
result = new float[l];
for (int i = 0; i < l; i++)
result[i] = readFloat();
return result;
}
public int[] readIntArray(int[] buffer) throws IOException {
int l = readInt();
if (l > SANITY_CHECK)
throw new IOException("Array length failed sanity check: " + l);
int[] result = buffer;
if ((buffer == null) || (l > buffer.length))
result = new int[l];
for (int i = 0; i < l; i++)
result[i] = readInt();
return result;
}
public String readString(int l) throws IOException {
byte[] ascii = new byte[l];
readFully(ascii);
pad();
return new String(ascii, "US-ASCII");
}
public String readString() throws IOException {
int l = readInt();
if (l > SANITY_CHECK)
throw new IOException("String length failed sanity check: " + l);
return readString(l);
}
private static final class CountedInputStream extends FilterInputStream {
private long count = 0;
private long limit = -1;
private long mark = 0;
CountedInputStream(InputStream in) {
super(in);
}
public long getBytesRead() {
return count;
}
public int available() throws IOException {
return Math.min((int) (limit - count), super.available());
}
public synchronized void mark(int readlimit) {
mark = count;
super.mark(readlimit);
}
public int read() throws IOException {
// int available = checkLimit(1);
int rc = super.read();
if (rc >= 0)
count++;
return rc;
}
public int read(byte[] data) throws IOException {
return read(data, 0, data.length);
}
public int read(byte[] data, int off, int len) throws IOException {
int available = checkLimit(len);
int rc = super.read(data, off, available);
if (rc > 0)
count += rc;
return rc;
}
public synchronized void reset() throws IOException {
count = mark;
super.reset();
}
public long skip(long bytes) throws IOException {
long available = checkLimit(bytes);
long rc = super.skip(available);
if (rc > 0)
count += rc;
return rc;
}
/**
* Sets a limit on the number of bytes that can be read from this file
* before an EOF will be generated
*/
void setReadLimit(int bytes) {
limit = count + bytes;
}
void clearReadLimit() {
limit = -1;
}
private int checkLimit(int request) throws IOException {
if (limit < 0)
return request;
else if (limit <= count)
throw new EOFException();
return Math.min(request, (int) (limit - count));
}
private long checkLimit(long request) throws IOException {
if (limit < 0)
return request;
else if (limit <= count)
throw new EOFException();
return Math.min(request, limit - count);
}
}
}