package hep.io.mcfio;
import hep.io.xdr.XDRBufferedRandomAccessFile;
import java.io.IOException;
import hep.io.xdr.XDRRandomAccessFile;
/**
* A class for writing MCFIO files.
*
* @author Tony Johnson (tonyj@slac.stanford.edu)
* @version $Id: MCFIOWriter.java 13660 2009-10-09 23:26:27Z tonyj $
*/
public class MCFIOWriter implements MCFIOConstants
{
protected static boolean compatibilityMode = true;
private FileHeader fileHeader;
private WriteEventTable eventTable;
private XDRRandomAccessFile xdr;
/**
* Open an MCFIO file for writing.
* @param title The title of the file
* @param comment The comment associate with the file
* @param numevts The number of events expected to be written
* @param blockIds The user defined blocks that will be included in this file
* @param blockNames Names for the blocks defined by blockIds
*/
public MCFIOWriter(String file, String title, String comment, int numevts, int[] blockIds, String[] blockNames) throws IOException
{
if (compatibilityMode)
{
if (title.length() > MCF_XDR_F_TITLE_LENGTH)
throw new MCFIOException("Title too long");
if (comment.length() > MCF_XDR_F_TITLE_LENGTH)
throw new MCFIOException("Comment too long");
}
xdr = new XDRBufferedRandomAccessFile(file,false,16192);
// Leave space for the fileHeader and eventTable
fileHeader = new FileHeader(getPosition(), title, comment, numevts, blockIds, blockNames);
xdr.seek(fileHeader.getLength());
fileHeader.setFirstTable(getPosition());
eventTable = new WriteEventTable(getPosition());
xdr.seek(getPosition() + eventTable.getLength());
}
/**
* Set compatibility mode. In the old C implementation
* there were various limits, such as the length of
* some strings and the maximum number of particles that
* could be written to stdhep events. There is no reason
* to have any of these limits in the Java implementation,
* but if we ignore them then the resulting file might not
* be readable by the old C implementation. By default this
* implementation enforces the same limits as the C implementation,
* but setting compatibilyMode to false will turn off this
* limitation.
*/
public void setCompatibilityMode(boolean mode)
{
compatibilityMode = mode;
}
public void close() throws IOException
{
eventTable.commit(xdr);
fileHeader.commit(xdr);
xdr.close();
}
/**
* Write an event
*/
public void write(MCFIOEvent event) throws IOException
{
if (eventTable.isFull())
eventTable = eventTable.newTable();
eventTable.add(event);
}
private int getPosition() throws IOException
{
// note: Java supports file positions specified as longs,
// but MCFIO only supports ints.
return (int) xdr.getFilePointer();
}
private class WriteEventTable extends EventTable
{
WriteEventTable(int pos) throws IOException
{
super(pos);
}
void add(MCFIOEvent event) throws IOException
{
super.add(event, getPosition());
// Write the event header
int nBlocks = event.getNBlocks();
int size = 4 * (12 + (nBlocks * 2));
xdr.writeInt(EVENTHEADER);
xdr.writeInt(size);
xdr.writeString("1.00");
xdr.writeInt(event.getEventNumber());
xdr.writeInt(event.getStoreNumber());
xdr.writeInt(event.getRunNumber());
xdr.writeInt(event.getTrigMask());
xdr.writeInt(nBlocks);
xdr.writeInt(nBlocks);
int[] ptrs = new int[nBlocks];
int[] ids = new int[nBlocks];
int pos = getPosition() + (4 * (2 + (nBlocks * 2)));
for (int i = 0; i < nBlocks; i++)
{
ids[i] = event.getBlockID(i);
ptrs[i] = pos;
pos += event.getBlock(i).getLength();
}
xdr.writeIntArray(ids);
xdr.writeIntArray(ptrs);
// Write the user blocks
for (int i = 0; i < nBlocks; i++)
{
event.getBlock(i).write(xdr);
}
}
void commit(XDRRandomAccessFile xdr) throws IOException
{
fileHeader.incrementNumEvents(numevts());
super.commit(xdr);
}
WriteEventTable newTable() throws IOException
{
// Commit the current table to disk
int currentPos = getPosition();
setNextTable(currentPos);
commit(xdr);
// leave space for the next event table
xdr.seek(currentPos + getLength());
return new WriteEventTable(currentPos);
}
}
}