// Copyright 2005, FreeHEP. package hep.graphics.heprep.wbxml; import hep.graphics.heprep.HepRep; import hep.graphics.heprep.HepRepAttValue; import hep.graphics.heprep.HepRepFactory; import hep.graphics.heprep.HepRepInstance; import hep.graphics.heprep.HepRepInstanceTree; import hep.graphics.heprep.HepRepPoint; import hep.graphics.heprep.HepRepTreeID; import hep.graphics.heprep.HepRepType; import hep.graphics.heprep.HepRepTypeTree; import hep.graphics.heprep.HepRepVersionException; import hep.graphics.heprep.ref.DefaultHepRepAttValue; import hep.graphics.heprep.ref.DefaultHepRepInstance; import hep.graphics.heprep.util.HepRepTypes; import hep.graphics.heprep.xml.XMLHepRepFactory; import java.awt.Color; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Stack; import java.util.StringTokenizer; import org.freehep.util.VersionComparator; import org.xmlpull.v1.XmlPullParserException; /** * Reader to read Binary HepRep streams/files and create a HepRep. * * @author Mark Donszelmann * @version $Id: BHepRepReader.java 8584 2006-08-10 23:06:37Z duns $ */ public class BHepRepReader extends BHepRepParser { /** * Minimally expected Binary HepRep version number */ public static final String expectedVersion = "2.0"; private HepRepFactory factory; private HepRep heprep; private int level = 0; private HepRepTypes types; private HepRepTypeTree currentTypeTree = null; private HepRepTreeID currentTypeTreeRef = null; private HepRepInstanceTree instanceTree = null; private HepRepPoint currentPoint = null; private boolean inPoint = false; private Stack/*<HepRepInstance>*/ instanceStack = new Stack(); private HepRepInstance currentInstance = null; private Stack/*<HepRepType>*/ typeStack = new Stack(); private HepRepType currentType = null; /** * Create a Binary HepRep Reader and add content to heprep * @param heprep heprep to add content to */ public BHepRepReader(HepRep heprep) { super(); this.heprep = heprep; factory = new XMLHepRepFactory(); } /** * Changes the names "valueString, valueBoolean" to "value" and sets an artifical attribute "*type" to * the integer value of the type. This only happens for the ATTVALUE tag. */ protected void addAttribute(int attId, String prefix, String namespace, String name, Object value) { if ((getTag() == ATTVALUE) && ((attId == VALUE_STRING) || (attId == VALUE_COLOR) || (attId == VALUE_LONG) || (attId == VALUE_INT) || (attId == VALUE_BOOLEAN) || (attId == VALUE_DOUBLE))) { super.addAttribute(attId, prefix, namespace, "*type", new Integer(attId)); super.addAttribute(attId, prefix, namespace, "value", value); return; } super.addAttribute(attId, prefix, namespace, name, value); } /** * Adds actual point. */ protected Object parseOpaque(int len, int tagId, int attId) throws IOException, XmlPullParserException { Object opaque = super.parseOpaque(len, tagId, attId); if ((tagId == 0) && (inPoint)) { // CONTENT of point (NOTE tagId not set at top-level) // NOTE: single precision only... // NOTE: length of points array is not accurate for number of points. double[] points = (double[])opaque; if ((len % 12) != 0) throw new XmlPullParserException(getClass()+": Point should have n*3*4 coordinates rather than "+len+"."); int nPoints = len / 4; if (nPoints == 3) { currentPoint = factory.createHepRepPoint(currentInstance, points[0], points[1], points[2]); } else { currentPoint = null; for (int i=0; i<nPoints; i+=3) { factory.createHepRepPoint(currentInstance, points[i], points[i+1], points[i+2]); } } } return opaque; } /** * Parse stream as Binary HepRep * @param in stream to parse * @throws XmlPullParserException in case format is incorrect * @throws IOException in case stream cannot be read */ public void parse(InputStream in) throws XmlPullParserException, IOException { setInput(in, null); int eventType = getEventType(); while (eventType != END_DOCUMENT) { switch (eventType) { case START_DOCUMENT: startDocument(); break; case END_DOCUMENT: endDocument(); break; case START_TAG: startTag(); break; case END_TAG: endTag(); break; case TEXT: text(); break; default: break; } eventType = next(); } } protected void startDocument() { types = new HepRepTypes(); currentTypeTree = null; currentTypeTreeRef = null; instanceTree = null; currentPoint = null; inPoint = false; instanceStack = new Stack(); currentInstance = null; typeStack = new Stack(); currentType = null; level = 0; } protected void endDocument() { } protected void startTag() throws XmlPullParserException { level++; switch (getTag()) { case HEPREP: { String version = getAttributeValue("version"); if (version != null) { VersionComparator comparator = new VersionComparator(); if (comparator.versionNumberCompare(version, expectedVersion) < 0) { throw new XmlPullParserException("Wrong version", this, new HepRepVersionException(getClass()+": Found version '"+version+"' while expected version '"+expectedVersion+"'.") ); } } else { throw new XmlPullParserException("Wrong version", this, new HepRepVersionException(getClass()+": Missing 'version' attribute on 'heprep' tag.") ); } break; } case ATTDEF: { if (currentType == null) { throw new XmlPullParserException(getClass()+": Cannot use 'attdef' outside 'type' tag."); } String name = getAttributeValue("name"); String desc = getAttributeValue("desc"); String category = getAttributeValue("category"); String extra = getAttributeValue("extra"); currentType.addAttDef(name, desc, category, extra); break; } case ATTVALUE: { String name = getAttributeValue("name"); Integer type = (Integer)getAttributeObject("*type"); Integer showLabelInt = (Integer)getAttributeObject("showlabel"); int showLabel = (showLabelInt == null) ? HepRepAttValue.SHOW_NONE : showLabelInt.intValue(); HepRepAttValue attValue; switch(type.intValue()) { case VALUE_STRING: attValue = new DefaultHepRepAttValue(name, getAttributeValue("value"), showLabel); break; case VALUE_COLOR: attValue = new DefaultHepRepAttValue(name, (Color)getAttributeObject("value"), showLabel); break; case VALUE_LONG: attValue = new DefaultHepRepAttValue(name, ((Long)getAttributeObject("value")).longValue(), showLabel); break; case VALUE_INT: attValue = new DefaultHepRepAttValue(name, ((Integer)getAttributeObject("value")).intValue(), showLabel); break; case VALUE_BOOLEAN: // NOTE: this is written as an ATTRVALUE and thus is resolved as string. attValue = new DefaultHepRepAttValue(name, ((String)getAttributeObject("value")).equalsIgnoreCase("true"), showLabel); break; case VALUE_DOUBLE: attValue = new DefaultHepRepAttValue(name, ((Double)getAttributeObject("value")).doubleValue(), showLabel); break; default: throw new XmlPullParserException(getClass()+": Unknown '*type' in 'attValue' tag: "+type.intValue()+"."); } if (currentPoint != null) { currentPoint.addAttValue(attValue); } else if (currentInstance != null) { currentInstance.addAttValue(attValue); } else if (currentType != null) { currentType.addAttValue(attValue); } else if (inPoint) { throw new XmlPullParserException(getClass()+": Coordinates of point need to come before the 'attvalue' tag."); } else { throw new XmlPullParserException(getClass()+": Cannot use 'attvalue' outside 'type', 'instance' or 'point' tag."); } break; } case INSTANCE: { String typeName = getAttributeValue("type"); if (typeName == null) { throw new XmlPullParserException(getClass()+": Instance cannot exist without referring to a type."); } HepRepType type = types.getType(currentTypeTreeRef, typeName, currentInstance); if (type == null) { throw new XmlPullParserException(getClass()+": Cannot find type: '"+typeName+"' "+ "in tree: '"+types.getID(currentTypeTreeRef)+"'"); } instanceStack.push(currentInstance); if (currentInstance != null) { currentInstance = factory.createHepRepInstance(currentInstance, type); } else { currentInstance = factory.createHepRepInstance(instanceTree, type); } break; } case TREEID: { String name = getAttributeValue("name"); String version = getAttributeValue("version"); String qualifier = getAttributeValue("qualifier"); instanceTree.addInstanceTree(factory.createHepRepTreeID(name, version, qualifier)); break; } case ACTION: { String name = getAttributeValue("name"); String expression = getAttributeValue("expression"); // FIXME: JHEPREP-3 factory.createHepRepAction(name, expression); break; } case INSTANCETREE: { String name = getAttributeValue("name"); String version = getAttributeValue("version"); currentTypeTreeRef = factory.createHepRepTreeID(getAttributeValue("typetreename"), getAttributeValue("typetreeversion")); instanceTree = factory.createHepRepInstanceTree(name, version, currentTypeTreeRef); heprep.addInstanceTree(instanceTree); break; } case TYPE: { String name = getAttributeValue("name"); typeStack.push(currentType); if (currentType != null) { currentType = factory.createHepRepType(currentType, name); } else { currentType = factory.createHepRepType(currentTypeTree, name); } types.put(currentTypeTree, name, currentType); break; } case TYPETREE: { String name = getAttributeValue("name"); String version = getAttributeValue("version"); HepRepTreeID id = factory.createHepRepTreeID(name, version); currentTypeTree = factory.createHepRepTypeTree(id); heprep.addTypeTree(currentTypeTree); types.put(id, currentTypeTree); break; } case LAYER: { String order = getAttributeValue("order"); StringTokenizer st = new StringTokenizer(order,","); while (st.hasMoreTokens()) { heprep.addLayer(st.nextToken().trim()); } break; } case POINT: { currentPoint = null; inPoint = true; break; } default: throw new XmlPullParserException(getClass()+": Unknown start tag: "+getTag()); } if (Thread.interrupted()) throw new XmlPullParserException(getClass()+": Interrupted", this, new InterruptedException()); } protected void endTag() throws XmlPullParserException { switch (getTag()) { case HEPREP: // ignored, toplevel already stored break; case ATTDEF: break; case ATTVALUE: break; case INSTANCE: if (currentInstance instanceof DefaultHepRepInstance) ((DefaultHepRepInstance)currentInstance).optimize(); currentInstance = (HepRepInstance)instanceStack.pop(); break; case TREEID: break; case ACTION: break; case INSTANCETREE: instanceTree = null; currentTypeTreeRef = null; break; case TYPE: currentType = (HepRepType)typeStack.pop(); break; case TYPETREE: currentTypeTree = null; break; case LAYER: break; case POINT: currentPoint = null; inPoint = false; break; default: throw new XmlPullParserException(getClass()+": Unknown end tag: "+getTag()); } if (Thread.interrupted()) throw new XmlPullParserException(getClass()+": Interrupted", this, new InterruptedException()); // make sure this is at the end, and that heprep is set! level--; } protected void text() { } /** * Small test * @param args binary heprep file * @throws XmlPullParserException for format problems * @throws IOException for read problems */ public static void main(String[] args) throws XmlPullParserException, IOException { System.out.println("Start"); BHepRepReader r = new BHepRepReader(new XMLHepRepFactory().createHepRep()); r.parse(new FileInputStream(args[0])); } }