// Copyright 2000-2003, FreeHEP.
package hep.graphics.heprep.ref;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import org.freehep.util.io.*;
import hep.graphics.heprep.*;
/**
* This abstract HepRep Reader handles ZipInputStreams, ZipFiles, reads the "heprep.properties"
* file, allows for properties to be quesried and handles files to be skipped while iterating.
* It assumes the concrete subclass has Sequential access. ZipFiles will provide Random access
* as well.
* The reset method should implement the opening of the file(s), or call super.reset().
* Reset should be called from the constructor to open the initial file.
*
* @author M.Donszelmann
*
* @version $Id: AbstractHepRepReader.java 8584 2006-08-10 23:06:37Z duns $
*/
public abstract class AbstractHepRepReader implements HepRepReader {
// NOTE: either of input or name is set.
protected InputStream input;
protected String name;
private ZipEntry entry;
private ZipInputStream zip;
protected ZipFile zipFile;
private Enumeration/*<ZipEntry>*/ zipEntries;
private int position;
private Properties properties;
private Set/*<String>*/ skip;
private AbstractHepRepReader() {
super();
properties = new Properties();
skip = new HashSet();
}
protected AbstractHepRepReader(InputStream in) throws IOException {
this();
input = in;
}
protected AbstractHepRepReader(String fileName) throws IOException {
this();
name = fileName;
}
public String getProperty(String key, String defaultValue) throws IOException {
return properties.getProperty(key, defaultValue);
}
public void close() throws IOException {
if (zip != null) {
zip.close();
}
if (zipFile != null) {
zipFile.close();
}
}
public boolean hasSequentialAccess() throws IOException {
return true;
}
public void reset() throws IOException, UnsupportedOperationException {
if (input instanceof ZipInputStream) {
zip = (ZipInputStream)input;
zip.reset();
} else if (name != null) {
if (name.toLowerCase().endsWith(".zip")) {
zipFile = new ZipFile(name);
zipEntries = zipFile.entries();
position = 0;
ZipEntry propEntry = zipFile.getEntry("heprep.properties");
if (propEntry != null) {
skip.add("heprep.properties");
InputStream propStream = zipFile.getInputStream(propEntry);
properties.load(propStream);
propStream.close();
String ignoreList = properties.getProperty("RecordLoop.ignore",null);
if (ignoreList != null) skip.addAll(Arrays.asList(ignoreList.split(":")));
}
}
}
}
public int size() {
if (zipFile != null) return zipFile.size() - skip.size();
return -1;
}
public int skip(int n) throws UnsupportedOperationException {
int i = n;
try {
while ((i > 0) && hasNext()) {
next();
i--;
}
} catch (IOException e) {
}
return n-i;
}
public boolean hasNext() throws IOException, UnsupportedOperationException {
if (zipFile != null) return (size() - position) > 0;
// best we can do here, since the zip.available() seems unreliable in an XML context
return true;
}
public HepRep next() throws IOException, UnsupportedOperationException, NoSuchElementException {
if (!hasNext()) throw new UnsupportedOperationException(getClass()+" no more elements");
if (zip != null) {
entry = zip.getNextEntry();
while (skip.contains(entry.getName())) {
entry = zip.getNextEntry();
}
InputStream stream = new BufferedInputStream(new NoCloseInputStream(zip));
return readHepRep(stream, entry.getName().endsWith(".bheprep"));
}
if (zipFile != null) {
entry = (ZipEntry)zipEntries.nextElement();
while (skip.contains(entry.getName())) {
entry = (ZipEntry)zipEntries.nextElement();
}
position++;
InputStream stream = zipFile.getInputStream(entry);
if (entry.getName().toLowerCase().endsWith(".gz")) {
stream = new GZIPInputStream(stream);
}
stream = new BufferedInputStream(stream);
HepRep heprep = readHepRep(stream, entry.getName().endsWith(".bheprep"));
// Merge in all related instance trees
// FIXME this merging should be available in a general fashion...
// FIXME, this does not work yet.
for (Iterator i=heprep.getInstanceTreeList().iterator(); i.hasNext(); ) {
HepRepInstanceTree tree = (HepRepInstanceTree)i.next();
// System.out.println(tree);
for (Iterator j=tree.getInstanceTreeList().iterator(); j.hasNext(); ) {
HepRepTreeID id = (HepRepTreeID)j.next();
String[] name = id.getName().split("#",2);
ZipEntry zipEntry = zipFile.getEntry(name[0]);
if (zipEntry != null) {
InputStream zipStream = new BufferedInputStream(zipFile.getInputStream(zipEntry));
HepRep h = readHepRep(zipStream, name[0].endsWith(".bheprep"));
for (Iterator k=h.getInstanceTreeList().iterator(); k.hasNext(); ) {
k.next();
}
}
}
// System.out.println("==");
}
return heprep;
}
return null;
}
public boolean hasRandomAccess() {
return zipFile != null;
}
public HepRep read(String name) throws IOException, UnsupportedOperationException, NoSuchElementException {
if (!hasRandomAccess()) throw new UnsupportedOperationException(getClass()+" does not support random access");
entry = zipFile.getEntry(name);
if (entry == null) throw new NoSuchElementException(getClass()+" cannot access entry '"+name+"'");
InputStream stream = new BufferedInputStream(zipFile.getInputStream(entry));
return readHepRep(stream, name.endsWith(".bheprep"));
}
public String entryName() {
return (entry != null) ? entry.getName() : null;
}
public List/*<String>*/ entryNames() {
if (zipFile == null) return null;
List list = new AbstractSequentialList() {
public int size() {
return AbstractHepRepReader.this.size();
}
public ListIterator listIterator(int index) {
final int startIndex = index;
return new ListIterator() {
private int position;
private Enumeration entries;
private ZipEntry entry;
{
entries = zipFile.entries();
position = startIndex;
for (int i=0; i<=position; i++) {
entry = entries.hasMoreElements() ? (ZipEntry)entries.nextElement() : null;
while ((entry != null) && skip.contains(entry.getName())) {
entry = entries.hasMoreElements() ? (ZipEntry)entries.nextElement() : null;
}
if (entry == null) break;
}
if (entry == null) position = size();
}
public void add(Object o) {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return entry != null;
}
public boolean hasPrevious() {
return false;
}
public Object next() {
if (entry == null) throw new NoSuchElementException();
return entry.getName();
}
public int nextIndex() {
return position;
}
public Object previous() {
throw new NoSuchElementException();
}
public int previousIndex() {
return position - 1;
}
public void remove() {
throw new UnsupportedOperationException();
}
public void set(Object o) {
throw new UnsupportedOperationException();
}
}; // ListIterator
}
}; // AbstractSequentialList
return list;
}
protected abstract HepRep readHepRep(InputStream input, boolean binary) throws IOException;
/**
* Reads the HepRep
* @param input stream to read from
* @return HepRep read
* @throws IOException if stream cannot be read
* @deprecated use readHepRep(InputStream, boolean) instead.
*/
protected HepRep readHepRep(InputStream input) throws IOException {
return readHepRep(input, false);
}
}