// Copyright 2000-2004, FreeHEP.
package hep.graphics.heprep1.xml;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.freehep.util.io.*;
import hep.graphics.heprep1.*;
import hep.graphics.heprep1.ref.*;
/**
*
* @author M.Donszelmann
*
* @version $Id: XMLHepRepReader.java 8584 2006-08-10 23:06:37Z duns $
*/
public class XMLHepRepReader 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 XMLSequence sequence;
/**
* Create a HepRep Reader for a stream
* @param input stream to read from
* @throws IOException if stream cannot be read
*/
public XMLHepRepReader(InputStream input) throws IOException {
this.input = input;
reset();
}
/**
* Create a HepRep Reader for filename
* @param name filename
* @throws IOException if file cannot be read
*/
public XMLHepRepReader(String name) throws IOException {
this.name = name;
reset();
}
protected HepRep readHepRep(InputStream stream) throws IOException {
HepRep heprep = new DefaultHepRep();
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
XMLReader reader = factory.newSAXParser().getXMLReader();
// reader.setFeature("http://xml.org/sax/features/validation", true);
Handler handler = new Handler(heprep);
reader.setContentHandler(handler);
reader.setDTDHandler(handler);
reader.setErrorHandler(handler);
reader.setEntityResolver(handler);
String attributesFile = "AttributeDefaults.xml";
InputStream attributes = this.getClass().getResourceAsStream(attributesFile);
if (attributes == null) throw new IOException(getClass()+": Could not find "+attributesFile);
InputSource ds = new InputSource(attributes);
reader.parse(ds);
// now read real document
InputSource is = new InputSource(stream);
reader.parse(is);
} catch (ParserConfigurationException e) {
IOException exception = new IOException();
exception.initCause(e);
throw exception;
} catch (SAXParseException e) {
IOException exception = new IOException();
exception.initCause(new SAXParseException(e.getMessage(), e.getPublicId(), e.getSystemId(), e.getLineNumber(), e.getColumnNumber()) {
public String getMessage() {
return "line "+getLineNumber()+" column "+getColumnNumber()+": "+super.getMessage();
}
});
throw exception;
} catch (SAXException e) {
IOException exception = new IOException();
exception.initCause(e);
throw exception;
}
return heprep;
}
class Handler extends DefaultHandler {
private Hashtable labelTable;
{
labelTable = new Hashtable(4);
labelTable.put("NONE", new Integer(HepRepAttValue.SHOW_NONE));
}
private HepRep heprep;
private Stack stack = new Stack(); // of parents
private DefaultHepRepAttribute parent = null;
/**
* Create a HepRep Handler
* @param heprep heprep to be populated
*/
public Handler(HepRep heprep) {
this.heprep = heprep;
}
public void startDocument() throws SAXException {
stack = new Stack();
parent = (DefaultHepRepAttribute)heprep;
}
public void startElement(String namespace, String tag, String qName, Attributes atts) throws SAXException {
// System.out.println(namespace+", "+tag+", "+qName);
if (tag.equals("point")) {
double x = Double.valueOf(atts.getValue("x")).doubleValue();
double y = Double.valueOf(atts.getValue("y")).doubleValue();
double z = Double.valueOf(atts.getValue("z")).doubleValue();
DefaultHepRepPoint node = new DefaultHepRepPoint(parent, x, y, z);
stack.push(parent);
parent = node;
} else if (tag.equals("primitive")) {
DefaultHepRepPrimitive node = new DefaultHepRepPrimitive(parent);
stack.push(parent);
parent = node;
} else if (tag.equals("instance")) {
DefaultHepRepInstance node = new DefaultHepRepInstance(parent);
stack.push(parent);
parent = node;
} else if (tag.equals("type")) {
String name = atts.getValue("name");
String version = atts.getValue("version");
DefaultHepRepType node = new DefaultHepRepType(parent, name, version);
stack.push(parent);
parent = node;
} else if (tag.equals("heprep")) {
// ignored: heprep already created
} else if (tag.equals("attvalue")) {
String name = atts.getValue("name");
String value = atts.getValue("value");
String labelString = atts.getValue("showLabel");
int showLabel = HepRepAttValue.SHOW_NONE;
if (labelString != null) {
StringTokenizer st = new StringTokenizer(labelString, ", ");
while (st.hasMoreTokens()) {
String label = st.nextToken();
Integer number = (Integer)labelTable.get(label);
if (number != null) {
showLabel += number.intValue();
} else {
showLabel += Integer.parseInt(label);
}
}
}
parent.addValue(name, value, showLabel);
} else if (tag.equals("attdef")) {
String name = atts.getValue("name");
String desc = atts.getValue("desc");
String type = atts.getValue("type");
String extra = atts.getValue("extra");
parent.addDefinition(name, desc, type, extra);
} else {
throw new SAXException("[XMLHepRepReader] Unknown tag: "+tag);
}
}
public void endElement(String namespace, String tag, String qName) throws SAXException {
// System.out.println("/"+namespace+", "+tag+", "+qName);
// FIXME: Xerces 1.1.1 seems to report qNames for tags in case the element is non empty
if (tag.lastIndexOf(':') >= 0) tag = tag.substring(tag.lastIndexOf(':')+1);
if (tag.equals("point")) {
parent = (DefaultHepRepAttribute)stack.pop();
} else if (tag.equals("primitive")) {
parent = (DefaultHepRepAttribute)stack.pop();
} else if (tag.equals("instance")) {
parent = (DefaultHepRepAttribute)stack.pop();
} else if (tag.equals("type")) {
parent = (DefaultHepRepAttribute)stack.pop();
} else if (tag.equals("heprep")) {
// ignored, toplevel already stored
} else if (tag.equals("attvalue")) {
} else if (tag.equals("attdef")) {
} else {
throw new SAXException("[XMLHepRepReader] Unknown tag: "+tag);
}
}
public InputSource resolveEntity(String publicId, String systemId) {
System.out.println("Resolving: "+systemId);
if (publicId != null) {
return null;
}
// try to open systemId directly
InputStream is = null;
URL url = null;
try {
url = new URL(systemId);
is = url.openStream();
} catch (MalformedURLException mfue) {
return null;
} catch (IOException ioe) {
// try to resolve systemId relative to object or class
String file = url.getFile().substring(url.getFile().lastIndexOf('/')+1);
is = XMLHepRepReader.this.getClass().getResourceAsStream(file);
if (is == null) {
is = XMLHepRepReader.class.getResourceAsStream(file);
}
}
return new InputSource(is);
}
} // class Handler
//
// HepRepReader interface (from HepRep2).
//
public void close() throws IOException {
if (zip != null) {
zip.close();
}
if (zipFile != null) {
zipFile.close();
}
if (sequence != null) {
sequence.close();
}
}
public boolean hasSequentialAccess() throws IOException {
return true;
}
public void reset() throws IOException, UnsupportedOperationException {
if ((input != null) && !(input instanceof ZipInputStream)) {
sequence = new XMLSequence(new BufferedInputStream(input));
} else if ((name != null) && !name.toLowerCase().endsWith(".zip")) {
if (sequence != null) sequence.close();
if (name.toLowerCase().endsWith(".gz")) {
sequence = new XMLSequence(new BufferedInputStream(new GZIPInputStream(new FileInputStream(name))));
} else {
sequence = new XMLSequence(new BufferedInputStream(new FileInputStream(name)));
}
} else {
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;
}
}
}
}
public int size() {
if (zipFile != null) return zipFile.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 (sequence != null) return sequence.hasNext();
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 (sequence != null) {
return readHepRep(sequence.next());
}
if (zip != null) {
entry = zip.getNextEntry();
InputStream stream = new BufferedInputStream(new NoCloseInputStream(zip));
return readHepRep(stream);
}
if (zipFile != null) {
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);
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);
}
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 XMLHepRepReader.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;
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;
}
}