package hep.io.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); } } }