/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * logisim-evolution is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.file; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.w3c.dom.Element; import com.cburch.draw.model.AbstractCanvasObject; import com.cburch.logisim.Main; import com.cburch.logisim.circuit.Circuit; import com.cburch.logisim.circuit.CircuitAttributes; import com.cburch.logisim.circuit.CircuitMutator; import com.cburch.logisim.circuit.CircuitTransaction; import com.cburch.logisim.circuit.Wire; import com.cburch.logisim.comp.Component; import com.cburch.logisim.comp.ComponentFactory; import com.cburch.logisim.data.AttributeSet; import com.cburch.logisim.data.Location; import com.cburch.logisim.tools.AddTool; import com.cburch.logisim.tools.Library; import com.cburch.logisim.tools.Tool; public class XmlCircuitReader extends CircuitTransaction { /** * Get a circuit's component from a read XML file. If the component has a * non-null "trackercomp" field, it means that it is tracked, therefore it * is skipped in the non-tracked version to avoid errors. * * @param elt * XML element to parse * @param reader * XML file reader * @return the component built from its XML description * @throws XmlReaderException */ static Component getComponent(Element elt, XmlReader.ReadContext reader) throws XmlReaderException { if (elt.getAttribute("trackercomp") != "" && !Main.VERSION.hasTracker()) { return (null); } // Determine the factory that creates this element String name = elt.getAttribute("name"); if (name == null || name.equals("")) { throw new XmlReaderException(Strings.get("compNameMissingError")); } String libName = elt.getAttribute("lib"); Library lib = reader.findLibrary(libName); if (lib == null) { throw new XmlReaderException(Strings.get("compUnknownError", "no-lib")); } Tool tool = lib.getTool(name); if (tool == null || !(tool instanceof AddTool)) { if (libName == null || libName.equals("")) { throw new XmlReaderException(Strings.get("compUnknownError", name)); } else { throw new XmlReaderException(Strings.get("compAbsentError", name, libName)); } } ComponentFactory source = ((AddTool) tool).getFactory(); // Determine attributes String loc_str = elt.getAttribute("loc"); AttributeSet attrs = source.createAttributeSet(); reader.initAttributeSet(elt, attrs, source); // Create component if location known if (loc_str == null || loc_str.equals("")) { throw new XmlReaderException(Strings.get("compLocMissingError", source.getName())); } else { try { Location loc = Location.parse(loc_str); return source.createComponent(loc, attrs); } catch (NumberFormatException e) { throw new XmlReaderException(Strings.get("compLocInvalidError", source.getName(), loc_str)); } } } private XmlReader.ReadContext reader; private List<XmlReader.CircuitData> circuitsData; public XmlCircuitReader(XmlReader.ReadContext reader, List<XmlReader.CircuitData> circDatas) { this.reader = reader; this.circuitsData = circDatas; } void addWire(Circuit dest, CircuitMutator mutator, Element elt) throws XmlReaderException { Location pt0; try { String str = elt.getAttribute("from"); if (str == null || str.equals("")) { throw new XmlReaderException( Strings.get("wireStartMissingError")); } pt0 = Location.parse(str); } catch (NumberFormatException e) { throw new XmlReaderException(Strings.get("wireStartInvalidError")); } Location pt1; try { String str = elt.getAttribute("to"); if (str == null || str.equals("")) { throw new XmlReaderException(Strings.get("wireEndMissingError")); } pt1 = Location.parse(str); } catch (NumberFormatException e) { throw new XmlReaderException(Strings.get("wireEndInvalidError")); } mutator.add(dest, Wire.create(pt0, pt1)); } private void buildCircuit(XmlReader.CircuitData circData, CircuitMutator mutator) { Element elt = circData.circuitElement; Circuit dest = circData.circuit; Map<Element, Component> knownComponents = circData.knownComponents; if (knownComponents == null) knownComponents = Collections.emptyMap(); try { /* Here we check the attribute circuitnamedbox for backwards compatibility */ boolean HasNamedBox = false; for (Element attrElt : XmlIterator.forChildElements(circData.circuitElement, "a")) { if (attrElt.hasAttribute("name")) { String Name = attrElt.getAttribute("name"); if (Name.equals("circuitnamedbox")) { HasNamedBox = true; } } } reader.initAttributeSet(circData.circuitElement, dest.getStaticAttributes(), null); if ((!HasNamedBox)&&circData.circuitElement.hasChildNodes()) { dest.getStaticAttributes().setValue(CircuitAttributes.NAMED_CIRCUIT_BOX, false); } } catch (XmlReaderException e) { reader.addErrors(e, circData.circuit.getName() + ".static"); } for (Element sub_elt : XmlIterator.forChildElements(elt)) { String sub_elt_name = sub_elt.getTagName(); if (sub_elt_name.equals("comp")) { try { Component comp = knownComponents.get(sub_elt); if (comp == null) { comp = getComponent(sub_elt, reader); } if (comp != null) { mutator.add(dest, comp); } } catch (XmlReaderException e) { reader.addErrors(e, circData.circuit.getName() + "." + toComponentString(sub_elt)); } } else if (sub_elt_name.equals("wire")) { try { addWire(dest, mutator, sub_elt); } catch (XmlReaderException e) { reader.addErrors(e, circData.circuit.getName() + "." + toWireString(sub_elt)); } } } List<AbstractCanvasObject> appearance = circData.appearance; if (appearance != null && !appearance.isEmpty()) { dest.getAppearance().setObjectsForce(appearance); dest.getAppearance().setDefaultAppearance(false); } } @Override protected Map<Circuit, Integer> getAccessedCircuits() { HashMap<Circuit, Integer> access = new HashMap<Circuit, Integer>(); for (XmlReader.CircuitData data : circuitsData) { access.put(data.circuit, READ_WRITE); } return access; } @Override protected void run(CircuitMutator mutator) { for (XmlReader.CircuitData circuitData : circuitsData) { buildCircuit(circuitData, mutator); } } private String toComponentString(Element elt) { String name = elt.getAttribute("name"); String loc = elt.getAttribute("loc"); return name + "(" + loc + ")"; } private String toWireString(Element elt) { String from = elt.getAttribute("from"); String to = elt.getAttribute("to"); return "w" + from + "-" + to; } }