package hep.io.root; import hep.io.root.core.DefaultClassFactory; import hep.io.root.core.FastInputStream; import hep.io.root.core.FileClassFactory; import hep.io.root.core.RootClassFactory; import hep.io.root.core.RootDaemonInputStream; import hep.io.root.core.RootInput; import hep.io.root.core.RootRandomAccessFile; import hep.io.root.daemon.DaemonInputStream; import hep.io.root.interfaces.TDatime; import hep.io.root.interfaces.TDirectory; import hep.io.root.interfaces.TFile; import hep.io.root.interfaces.TKey; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; /** * A class for reading root files. * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: RootFileReader.java 13538 2008-07-24 15:35:06Z tonyj $ */ public class RootFileReader implements TFile { private static boolean welcome = false; private static boolean debug = System.getProperty("debugRoot") != null; private ClassLoader classLoader; private java.util.Date fDatimeC; private java.util.Date fDatimeM; private RootClass fileClass; private RootClassFactory factory; private RootInput in; private String name; private String title; private TDirectory dir; private TKey streamerInfo; private int fNbytesKeys; private int fNbytesName; private long fSeekDir; private long fSeekKeys; private long fSeekParent; private int fVersion; private long fSeekInfo; /** * Open a file specified by URL for reading. * The URL may point to * <ul> * <li>a file, * <li>to a rootd daemon (root: protocol) * <li>to any other data (not yet implemented) * </ul> * source. In the last case the file will be buffered in memory prior to * reading, so this method should only be used for small files. * <p> * The options argument is used to pass options to the file reader. Supported * option include: * <ul> * <li>scheme -- The authorization scheme, currently supported UsrPwd, Anonymous * <li>user -- The user name to use * <li>password -- The password to use * </ul> * The shared parameter may be used to pass an already open RootFileReader. In this case * the files will share the same cache or loaded RootClass's. This will speed up opening * many files, but will only work if the files contain the same root classes. */ public RootFileReader(URL url, Map options, RootFileReader shared) throws IOException { if (url.getProtocol().equals("file")) init(new File(url.getFile()),shared); else { URLConnection connection = url.openConnection(); if (options != null) { Object user = options.get("user"); if (user != null) connection.setRequestProperty("user", user.toString()); Object pass = options.get("password"); if (pass != null) connection.setRequestProperty("password", pass.toString()); Object mode = options.get("scheme"); if (mode != null) connection.setRequestProperty("scheme", mode.toString()); Object bufferSize = options.get("bufferSize"); if (bufferSize != null) connection.setRequestProperty("bufferSize", bufferSize.toString()); } InputStream source = connection.getInputStream(); if (source instanceof DaemonInputStream) init(new RootDaemonInputStream((DaemonInputStream) source,this),shared); else { throw new IOException("Unsupported protocol: "+url.getProtocol() ); // if ((source.readByte() != 'r') || (source.readByte() != 'o') || (source.readByte() != 'o') || (source.readByte() != 't')) // throw new IOException("Not a root file"); // ByteArrayOutputStream out = new ByteArrayOutputStream(); // byte[] buffer = new byte[8192]; // for (;;) // { // int l = source.read(buffer); // if (l<0) break; // out.write(buffer,0,l); // } // source.close(); // out.close(); // init(new RootInputStream(new RootByteArrayInputStream(out.toByteArray(),0),this); } } } public RootFileReader(URL url, Map options) throws IOException { this(url,options,null); } /** * Open a file specified by URL for reading with the default options. */ public RootFileReader(URL url) throws IOException { this(url,null); } /** * Open a root file for reading. * The DefaultClassFactory will be used for creating classes * @param file The name of the file to open * @throws IOException If the file cannot be opened */ public RootFileReader(String file) throws IOException { init(new File(file),null); } /** * Open a root file for reading * @param file The file to open */ public RootFileReader(File file) throws IOException { init(file,null); } public RootFileReader(File file, RootFileReader shared) throws IOException { init(file,shared); } private void init(File file, RootFileReader shared) throws IOException { RootRandomAccessFile raf = new RootRandomAccessFile(file, this); RootInput in = raf; if (System.getProperty("useNIO") != null) in = new FastInputStream(this, raf); init(in, shared); } private void init(RootInput in, RootFileReader shared) throws IOException { try { this.in = in; if (!welcome) welcome(); factory = new DefaultClassFactory(this); fileClass = factory.create("TFile"); fVersion = in.readInt(); if (fVersion < 30006) throw new IOException("hep.io.root package cannot read files created by Root before release 3.00/6 (" + fVersion + ")"); if (debug) System.out.println("version=" + fVersion); boolean fLargeFile = fVersion > 1000000; fVersion %= 1000000; int fBEGIN = in.readInt(); if (fLargeFile) { long fEND = in.readLong(); long fSeekFree = in.readLong(); int fNbytesFree = in.readInt(); int nfree = in.readInt(); fNbytesName = in.readInt(); int fUnits = in.readByte(); int fCompress = in.readInt(); fSeekInfo = in.readLong(); int fNBytesInfo = in.readInt(); } else { int fEND = in.readInt(); int fSeekFree = in.readInt(); int fNbytesFree = in.readInt(); int nfree = in.readInt(); fNbytesName = in.readInt(); int fUnits = in.readByte(); int fCompress = in.readInt(); fSeekInfo = in.readInt(); int fNBytesInfo = in.readInt(); } in.setPosition(fBEGIN); int Nbytes = in.readInt(); int version = in.readShort(); int ObjLen = in.readInt(); fDatimeC = fDatimeM = ((TDatime) in.readObject("TDatime")).getDate(); int KeyLen = in.readShort(); int Cycle = in.readShort(); long fSeekKey; long fSeekPdir; if (version > 1000) { fSeekKey = in.readLong(); fSeekPdir = in.readLong(); } else { fSeekKey = in.readInt(); fSeekPdir = in.readInt(); } String className = in.readObject("TString").toString(); name = in.readObject("TString").toString(); title = in.readObject("TString").toString(); in.setPosition(fBEGIN + fNbytesName); // This should get us to the directory dir = (TDirectory) in.readObject("TDirectory"); if (fSeekInfo == 0) recover(fBEGIN); if (shared != null) { this.factory = shared.factory; } else if (fSeekInfo != 0) { in.setPosition(fSeekInfo); streamerInfo = (TKey) in.readObject("TKey"); this.factory = new FileClassFactory(streamerInfo, factory, this); } else throw new IOException("Could not located StreamerInfo in root file"); } catch (RootClassNotFound xr) { IOException x = new IOException("Root Class Not Found: " + xr.getClassName()); x.initCause(xr); throw x; } } private void recover(int begin) throws IOException { if (debug) System.err.println("File recovery in process"); long idcur = begin; int nread = 1024; for (;;) { in.setPosition(idcur); int nbytes = in.readInt(); if (nbytes < 0) // freespace { idcur -= nbytes; } else { int v = in.readVersion(); int fObjlen = in.readInt(); java.util.Date fDatime = ((hep.io.root.interfaces.TDatime) in.readObject("TDatime")).getDate(); int fKeylen = in.readShort(); int fCycle = in.readShort(); if (v > 1000) { long fSeekKey = in.readLong(); long fSeekPdir = in.readLong(); } else { int fSeekKey = in.readInt(); int fSeekPdir = in.readInt(); } String fClassName = in.readObject("TString").toString(); String fName = in.readObject("TString").toString(); String fTitle = in.readObject("TString").toString(); if ("StreamerInfo".equals(fName)) fSeekInfo = idcur; idcur += nbytes; } } } public int getBits() { return 0; } public RootClassFactory getClassFactory() { return factory; } /** * Set the classloader to use for checking for interfaces and loading proxies. */ public void setClassLoader(ClassLoader loader) { classLoader = loader; } public ClassLoader getClassLoader() { return classLoader; } public java.util.Date getDatimeC() { return fDatimeC; } public java.util.Date getDatimeM() { return fDatimeM; } public RootClassFactory getFactory() { return factory; } public TKey getKey(int index) { return dir.getKey(index); } public TKey getKey(String name) { return dir.getKey(name); } public TKey getKey(String name, int cycle) { return dir.getKey(name, cycle); } public TKey getKeyForTitle(String name) { return dir.getKeyForTitle(name); } public boolean hasKey(String name, int cycle) { return dir.hasKey(name,cycle); } public boolean hasKey(String name) { return dir.hasKey(name); } public String getName() { return name; } public int getNbytesKeys() { return fNbytesKeys; } public int getNbytesName() { return fNbytesName; } /** * Get the class of this object * @return The RootClass for this object */ public RootClass getRootClass() { return fileClass; } public long getSeekDir() { return fSeekDir; } public long getSeekKeys() { return fSeekKeys; } public long getSeekParent() { return fSeekParent; } public String getTitle() { return title; } public int getUniqueID() { return 0; } public int getVersion() { return fVersion; } public void close() throws IOException { in.close(); } /** * Get the object associated with a particular key */ public Object get(String name) throws IOException, RootClassNotFound { TKey key = getKey(name); return key.getObject(); } public int nKeys() { return dir.nKeys(); } /** * Get the StreamerInfo */ public List streamerInfo() throws IOException { try { return (List) streamerInfo.getObject(); } catch (RootClassNotFound x) { throw new IOException("Root Class Not Found during IO: " + x); } } public TKey streamerInfoKey() { return streamerInfo; } private static void welcome() { System.out.println("Root IO for Java, part of the FreeHEP library: http://java.freehep.org"); System.out.println("Please report all bugs/problems to tonyj@slac.stanford.edu"); System.out.println("Version $Id: RootFileReader.java 13538 2008-07-24 15:35:06Z tonyj $"); welcome = true; } }