package hep.io.xdr;
import java.io.File;
import java.io.IOException;
/**
* The performance of XDRRandomAccessFile used directly is
* pretty appaling. This is a buffered implementation
* that is much faster so long as it is used mostly for reading or mostly
* for writing.
*/
public class XDRBufferedRandomAccessFile extends XDRRandomAccessFile
{
private byte[] buffer;
private long offset; // Offset of buffer relative to base
private int pos; // Current position in buffer
private int used; // Number of bytes written or available in buffer
private final boolean readOnly;
private boolean readMode;
public XDRBufferedRandomAccessFile(String name, boolean readOnly, int bufferSize) throws IOException
{
super(name, readOnly ? "r" : "rw");
this.readOnly = readOnly;
this.readMode = readOnly;
buffer = new byte[bufferSize];
}
public XDRBufferedRandomAccessFile(File file, boolean readOnly, int bufferSize) throws IOException
{
super(file, readOnly ? "r" : "rw");
this.readOnly = readOnly;
this.readMode = readOnly;
buffer = new byte[bufferSize];
}
private void setReadMode(boolean readMode) throws IOException
{
if (this.readMode != readMode)
{
flush();
this.readMode = readMode;
}
}
private void checkCanRead() throws IOException
{
setReadMode(true);
}
private void checkCanWrite() throws IOException
{
if (readOnly)
{
throw new IOException("Can not write to read-only file");
}
setReadMode(false);
}
public long getFilePointer() throws IOException
{
return offset + pos;
}
public void close() throws IOException
{
if (!readMode)
{
flush();
}
super.close();
buffer = null;
}
public void flush() throws IOException
{
if (used > 0)
{
if (readMode)
{
offset += pos;
super.seek(offset);
}
else
{
super.write(buffer, 0, used);
offset += used;
}
}
used = 0;
pos = 0;
}
private void loadBuffer() throws IOException
{
offset += used;
used = super.read(buffer);
pos = 0;
}
public int read() throws IOException
{
checkCanRead();
if (pos >= used)
{
loadBuffer();
if (used < 0)
{
return -1;
}
}
return buffer[pos++] & 0xff;
}
public int read(byte[] buf) throws IOException
{
return read(buf, 0, buf.length);
}
public int read(byte[] buf, int start, int length) throws IOException
{
checkCanRead();
int available = used - pos;
if (available <= 0)
{
loadBuffer();
if (used < 0)
{
return -1;
}
available = used - pos;
}
int bytesToCopy = Math.min(available, length);
System.arraycopy(buffer, pos, buf, start, bytesToCopy);
pos += bytesToCopy;
return bytesToCopy;
}
public void seek(long position) throws IOException
{
if ((position >= offset) && (position <= (offset + used)))
{
pos = (int) (position - offset);
}
else
{
if (readMode)
{
super.seek(position);
offset = position;
used = 0;
pos = 0;
}
else
{
flush();
offset = position;
super.seek(offset);
}
}
}
public void write(byte[] buf, int start, int len) throws IOException
{
checkCanWrite();
if ((buffer.length - pos) <= len)
{
System.arraycopy(buf, start, buffer, pos, len);
pos += len;
if (pos > used)
{
used = pos;
}
}
else
{
used = pos;
flush();
super.write(buf, start, len);
offset += len;
}
}
public void write(byte[] buf) throws IOException
{
write(buf, 0, buf.length);
}
public void write(int b) throws IOException
{
checkCanWrite();
if (pos == buffer.length)
{
flush();
}
buffer[pos++] = (byte) b;
if (pos > used)
{
used = pos;
}
}
}