package hep.io.root.core;
import hep.io.root.RootFileReader;
import hep.io.root.RootObject;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.zip.Inflater;
/**
*
* @author tonyj
* @version $Id: FastInputStream.java 13617 2009-04-09 22:48:46Z tonyj $
*/
public class FastInputStream implements RootInput
{
private static long elapsed;
private static long invocations;
private ByteBuffer buffer;
private FastInputStream top;
private HashMap map = new HashMap();
private RootFileReader rfr;
private byte[] in;
private byte[] out;
private int offset;
private RandomAccessFile raf;
public FastInputStream(RootFileReader rfr, RandomAccessFile raf) throws IOException
{
this.rfr = rfr;
this.top = this;
this.raf = raf;
FileChannel channel = raf.getChannel();
this.buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, (int) raf.length());
buffer.getInt(); // Skip "root"
}
private FastInputStream(ByteBuffer buffer, FastInputStream top)
{
this.buffer = buffer;
this.top = top;
}
public RootClassFactory getFactory()
{
return top.rfr.getFactory();
}
public void setMap(int offset)
{
this.offset = offset - buffer.position();
}
public void setPosition(long pos) throws IOException
{
buffer.position((int) pos - offset);
}
public long getPosition() throws IOException
{
return buffer.position() + offset;
}
public int getRootVersion()
{
return top.rfr.getVersion();
}
public RootInput getTop()
{
return top;
}
public void checkLength(AbstractRootObject obj) throws IOException
{
obj.checkLength(buffer.position());
}
public void clearMap()
{
map.clear();
offset = 0;
}
public void dump()
{
System.out.println("Decompressing took " + elapsed + "ms (" + invocations + ")");
System.out.println("in size = " + in.length);
System.out.println("out size = " + out.length);
}
public int readArray(short[] data) throws IOException
{
int n = buffer.getInt();
buffer.asShortBuffer().get(data, 0, n);
buffer.position(buffer.position() + (n * 2));
return n;
}
public int readArray(byte[] data) throws IOException
{
int n = buffer.getInt();
buffer.get(data, 0, n);
return n;
}
public int readArray(double[] data) throws IOException
{
int n = buffer.getInt();
buffer.asDoubleBuffer().get(data, 0, n);
buffer.position(buffer.position() + (n * 8));
return n;
}
public int readArray(float[] data) throws IOException
{
int n = buffer.getInt();
buffer.asFloatBuffer().get(data, 0, n);
buffer.position(buffer.position() + (n * 4));
return n;
}
public int readArray(int[] data) throws IOException
{
int n = buffer.getInt();
buffer.asIntBuffer().get(data, 0, n);
buffer.position(buffer.position() + (n * 4));
return n;
}
public boolean readBoolean() throws java.io.IOException
{
return buffer.get() != 0;
}
public byte readByte() throws java.io.IOException
{
return buffer.get();
}
public char readChar() throws java.io.IOException
{
return buffer.getChar();
}
public double readDouble() throws java.io.IOException
{
return buffer.getDouble();
}
public double readTwistedDouble() throws java.io.IOException
{
int i1 = buffer.getInt();
int i2 = buffer.getInt();
long val = i1 + (((long) i2)<<32);
return Double.longBitsToDouble(val);
}
public void readFixedArray(byte[] data) throws IOException
{
buffer.get(data);
}
public void readFixedArray(double[] data) throws IOException
{
buffer.asDoubleBuffer().get(data);
buffer.position(buffer.position() + (data.length * 8));
}
public void readFixedArray(int[] data) throws IOException
{
buffer.asIntBuffer().get(data);
buffer.position(buffer.position() + (data.length * 4));
}
public void readFixedArray(long[] data) throws IOException
{
buffer.asLongBuffer().get(data);
buffer.position(buffer.position() + (data.length * 8));
}
public void readFixedArray(float[] data) throws IOException
{
buffer.asFloatBuffer().get(data);
buffer.position(buffer.position() + (data.length * 4));
}
public void readFixedArray(short[] data) throws IOException
{
buffer.asShortBuffer().get(data);
buffer.position(buffer.position() + (data.length * 2));
}
public float readFloat() throws java.io.IOException
{
return buffer.getFloat();
}
public void readFully(byte[] values) throws java.io.IOException
{
buffer.get(values);
}
public void readFully(byte[] values, int param, int param2) throws java.io.IOException
{
buffer.get(values, param, param2);
}
public int readInt() throws java.io.IOException
{
return buffer.getInt();
}
public String readLine() throws java.io.IOException
{
throw new IOException("Unimplemented method: readLine");
}
public long readLong() throws java.io.IOException
{
return buffer.getLong();
}
public void readMultiArray(Object[] array) throws IOException
{
for (int i = 0; i < array.length; i++)
{
Object o = array[i];
if (o instanceof double[])
readFixedArray((double[]) o);
else if (o instanceof float[])
readFixedArray((float[]) o);
else if (o instanceof short[])
readFixedArray((short[]) o);
else if (o instanceof byte[])
readFixedArray((byte[]) o);
else if (o instanceof int[])
readFixedArray((int[]) o);
else if (o instanceof long[])
readFixedArray((long[]) o);
else if (o instanceof Object[])
readMultiArray((Object[]) o);
else
throw new IOException("Unknown multiarray element: "+o.getClass());
}
}
public String readNullTerminatedString(int maxLength) throws IOException
{
int actualLength = maxLength - 1;
byte[] data = new byte[maxLength];
for (int i = 0; i < maxLength; i++)
{
data[i] = buffer.get();
if (data[i] == 0)
{
actualLength = i;
break;
}
}
return new String(data, 0, actualLength);
}
public RootObject readObject(String type) throws IOException
{
return RootInputStream.readObject(this, type);
}
public RootObject readObjectRef() throws IOException
{
return RootInputStream.readObjectRef(this, map);
}
public short readShort() throws java.io.IOException
{
return buffer.getShort();
}
public String readString() throws IOException
{
int l = buffer.get();
byte[] data = new byte[l];
buffer.get(data);
return new String(data);
}
public String readUTF() throws java.io.IOException
{
return DataInputStream.readUTF(this);
}
public int readUnsignedByte() throws java.io.IOException
{
int result = buffer.get();
if (result < 0)
result += 256;
return result;
}
public int readUnsignedShort() throws java.io.IOException
{
int result = buffer.getShort();
if (result < 0)
result += 65536;
return result;
}
public int readVersion() throws IOException
{
return readVersion(null);
}
public int readVersion(AbstractRootObject obj) throws IOException
{
int version = buffer.getShort();
if ((version & 0x4000) == 0)
return version;
int byteCount = ((version & 0x3fff) << 16) + readUnsignedShort();
if (obj != null)
obj.setExpectedLength(buffer.position(), byteCount);
return buffer.getShort();
}
public void skipObject() throws IOException
{
RootInputStream.skipObject(this);
}
public int skipBytes(int param) throws java.io.IOException
{
buffer.position(buffer.position() + param);
return param;
}
public RootInput slice(int size) throws IOException
{
int oldLimit = buffer.limit();
buffer.limit(buffer.position() + size);
ByteBuffer slice = buffer.slice();
buffer.position(buffer.limit());
buffer.limit(oldLimit);
return new FastInputStream(slice, top);
}
public RootInput slice(int inSize, int outSize) throws IOException
{
long start = System.currentTimeMillis();
if (in == null)
in = new byte[32768];
if (out == null)
out = new byte[65536];
int nout = 0;
int nin = 0;
ByteBuffer slice = ByteBuffer.allocateDirect(outSize);
Inflater inf = new Inflater(true);
try
{
while (nout < outSize)
{
inf.reset();
// root adds 9 bytes of header which are not needed
nin += 9;
buffer.position(buffer.position() + 9);
outer: while (true)
{
int rc;
while ((rc = inf.inflate(out)) == 0)
{
if (inf.finished() || inf.needsDictionary())
break outer;
if (inf.needsInput())
{
int l = Math.min(inSize - nin, in.length);
if (l == 0)
break outer;
buffer.get(in, 0, l);
inf.setInput(in, 0, l);
nin += l;
}
}
slice.put(out, 0, rc);
nout += rc;
}
int back = inf.getRemaining();
nin -= back;
buffer.position(buffer.position() - back);
}
slice.rewind();
long end = System.currentTimeMillis();
elapsed += (end - start);
invocations++;
return new FastInputStream(slice, top);
}
catch (Exception x)
{
IOException io = new IOException("Error during decompression");
io.initCause(x);
throw io;
}
finally
{
inf.end();
}
}
public void close() throws IOException
{
raf.close();
}
}