/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: XmlParam.java
*
* Copyright (c) 2003 Sun Microsystems and Static Free Software
*
* Electric(tm) 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.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.technology.xml;
import com.sun.electric.database.geometry.EGraphics;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.geometry.Poly.Type;
import com.sun.electric.technology.DRCTemplate;
import com.sun.electric.technology.EdgeH;
import com.sun.electric.technology.EdgeV;
import com.sun.electric.technology.Technology.TechPoint;
import com.sun.electric.tool.Job;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
*
*/
public class XmlParam {
public static class Technology implements Serializable {
public String techName;
public String className;
public String shortTechName;
public String description;
public int minNumMetals;
public int maxNumMetals;
public int defaultNumMetals;
public double scaleValue;
public boolean scaleRelevant;
public String defaultFoundry;
public double minResistance;
public double minCapacitance;
private final LinkedHashMap<String,Layer> layers = new LinkedHashMap<String,Layer>();
public final List<ArcProto> arcs = new ArrayList<ArcProto>();
public final List<PrimitiveNode> nodes = new ArrayList<PrimitiveNode>();
public final List<SpiceHeader> spiceHeaders = new ArrayList<SpiceHeader>();
public final List<DisplayStyle> displayStyles = new ArrayList<DisplayStyle>();
public MenuPalette menuPalette;
public final LinkedHashMap<String,RuleSet> ruleSets = new LinkedHashMap<String,RuleSet>();
public final List<Foundry> foundries = new ArrayList<Foundry>();
public Layer newLayer(String name) {
if (name == null)
throw new NullPointerException();
if (layers.containsKey(name))
throw new IllegalArgumentException("Duplicate Layer " + name);
Layer layer = new Layer(name);
layers.put(name, layer);
return layer;
}
public RuleSet newRuleSet(String name) {
if (name == null)
throw new NullPointerException();
if (ruleSets.containsKey(name))
throw new IllegalArgumentException("Duplicate RuleSet " + name);
RuleSet ruleSet = new RuleSet(name);
ruleSets.put(name, ruleSet);
return ruleSet;
}
public Layer findLayer(String name) {
return layers.get(name);
}
public ArcProto findArc(String name) {
for (ArcProto arc: arcs) {
if (arc.name.equals(name))
return arc;
}
return null;
}
public PrimitiveNode findNode(String name) {
for (PrimitiveNode node: nodes) {
if (node.name.equals(name))
return node;
}
return null;
}
public void writeXml(String fileName) {
try {
PrintWriter out = new PrintWriter(fileName);
Writer writer = new Writer(out);
writer.writeTechnology(this);
out.close();
System.out.println("Wrote " + fileName);
System.out.println(" (Add this file to the 'Added Technologies' Project Preferences to install it in Electric)");
} catch (IOException e) {
System.out.println("Error creating " + fileName);
}
}
}
public static class Layer implements Serializable {
public final String name;
public com.sun.electric.technology.Layer.Function function;
public int extraFunction;
public String cif;
public String skill;
public double resistance;
public double capacitance;
public double edgeCapacitance;
public PureLayerNode pureLayerNode;
private Layer(String name) {
this.name = name;
}
}
public static class PureLayerNode implements Serializable {
public String name;
public String oldName;
public Type style;
public String port;
public final List<String> portArcs = new ArrayList<String>();
}
public static class ArcProto implements Serializable {
public String name;
public String oldName;
public com.sun.electric.technology.ArcProto.Function function;
public boolean wipable;
public boolean curvable;
public boolean special;
public boolean notUsed;
public boolean skipSizeInPalette;
public boolean extended;
public boolean fixedAngle;
public int angleIncrement;
public double antennaRatio;
public double elibWidthOffset;
public final List<ArcLayer> arcLayers = new ArrayList<ArcLayer>();
public ArcPin arcPin;
}
public static class ArcPin implements Serializable {
public String name;
public String portName;
public double elibSize;
public final List<String> portArcs = new ArrayList<String>();
}
public static class ArcLayer implements Serializable {
public String layer;
public final Distance extend = new Distance();
public Type style;
}
public static class PrimitiveNode implements Serializable {
public String name;
public String oldName;
public boolean shrinkArcs;
public boolean square;
public boolean canBeZeroSize;
public boolean wipes;
public boolean lockable;
public boolean edgeSelect;
public boolean skipSizeInPalette;
public boolean notUsed;
public boolean lowVt;
public boolean highVt;
public boolean nativeBit;
public boolean od18;
public boolean od25;
public boolean od33;
public com.sun.electric.technology.PrimitiveNode.Function function;
public EPoint diskOffset;
public final Distance defaultWidth = new Distance();
public final Distance defaultHeight = new Distance();
public ERectangle nodeBase;
public final List<NodeLayer> nodeLayers = new ArrayList<NodeLayer>();
public final List<PrimitivePort> ports = new ArrayList<PrimitivePort>();
public int specialType;
public double[] specialValues;
public NodeSizeRule nodeSizeRule;
public String spiceTemplate;
}
public static class NodeLayer implements Serializable {
public String layer;
public Type style;
public int portNum;
public boolean inLayers;
public boolean inElectricalLayers;
public int representation;
public final Distance lx = new Distance();
public final Distance hx = new Distance();
public final Distance ly = new Distance();
public final Distance hy = new Distance();
public final List<TechPoint> techPoints = new ArrayList<TechPoint>();
public double sizex, sizey, sep1d, sep2d;
public String sizeRule, sepRule, sepRule2D;
public double lWidth, rWidth, tExtent, bExtent;
}
public static class NodeSizeRule implements Serializable {
public double width;
public double height;
public String rule;
}
public static class PrimitivePort implements Serializable {
public String name;
public int portAngle;
public int portRange;
public int portTopology;
public final Distance lx = new Distance();
public final Distance hx = new Distance();
public final Distance ly = new Distance();
public final Distance hy = new Distance();
public final List<String> portArcs = new ArrayList<String>();
}
public static class SpiceHeader implements Serializable {
public int level;
public final List<String> spiceLines = new ArrayList<String>();
}
public static class DisplayStyle implements Serializable {
public String name;
public final List<Color> transparentLayers = new ArrayList<Color>();
private final LinkedHashMap<Layer,LayerDisplayStyle> layerStylesInternal = new LinkedHashMap<Layer,LayerDisplayStyle>();
public final Map<Layer,LayerDisplayStyle> layerStyles = Collections.unmodifiableMap(layerStylesInternal);
public LayerDisplayStyle newLayer(Layer layer) {
LayerDisplayStyle lds = new LayerDisplayStyle(layer);
LayerDisplayStyle old = layerStylesInternal.put(layer, lds);
assert old == null;
return lds;
}
}
public static class LayerDisplayStyle implements Serializable {
public final Layer layer;
public EGraphics desc;
public String mode3D;
public double factor3D;
private LayerDisplayStyle(Layer layer) {
this.layer = layer;
}
}
public static class MenuPalette implements Serializable {
public int numColumns;
public List<List<Object>> menuBoxes = new ArrayList<List<Object>>();
public String writeXml() {
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
OneLineWriter writer = new OneLineWriter(out);
writer.writeMenuPaletteXml(this);
out.close();
return sw.getBuffer().toString();
}
}
public static class MenuNodeInst implements Serializable {
public String protoName;
public com.sun.electric.technology.PrimitiveNode.Function function;
public String text;
public double fontSize;
public int rotation;
}
public static class MenuCell implements Serializable {
public String cellName;
// public String text;
// public double fontSize;
}
public static class Distance implements Serializable {
public double k;
public double lambdaValue;
public final List<DistanceRule> terms = new ArrayList<DistanceRule>();
public void assign(Distance d) {
k = d.k;
lambdaValue = d.lambdaValue;
for (DistanceRule term: d.terms)
terms.add(term.clone());
}
// public void assign(com.sun.electric.technology.Technology.Distance d) {
// k = d.k;
// lambdaValue = d.lambdaValue;
// for (com.sun.electric.technology.Technology.DistanceRule term: d.terms)
// terms.add(new DistanceRule(term));
// }
public Distance clone() {
Distance d = new Distance();
d.assign(this);
return d;
}
public double getLambda(DistanceContext context) {
double value = lambdaValue;
for (DistanceRule term: terms)
value += term.getLambda(context);
return value;
}
private void writeXml(Writer writer, boolean multiLine) {
for (DistanceRule term: terms) {
term.writeXml(writer);
if (multiLine)
writer.l();
}
if (lambdaValue != 0) {
writer.bcpe(XmlKeyword.lambda, lambdaValue);
if (multiLine)
writer.l();
}
}
public void addLambda(double value) {
lambdaValue += value;
}
public void addRule(String ruleName, double k) {
addRule(ruleName, null, k);
}
public void addRule(String ruleName, Layer layer, double k) {
addRule(ruleName, layer, null, k);
}
public void addRule(String ruleName, Layer layer, Layer layer2, double k) {
terms.add(new DistanceRule(ruleName, layer, layer2, k));
}
public boolean isEmpty() { return lambdaValue == 0 && terms.isEmpty(); }
}
public static interface DistanceContext {
public double getRule(String ruleName);
}
public static class DistanceRule implements Serializable, Cloneable {
final String ruleName;
final Layer layer;
final Layer layer2;
final double k;
// public DistanceRule(com.sun.electric.technology.Technology.DistanceRule oldRule) {
// this(oldRule.ruleName, null, null, oldRule.k);
// }
private DistanceRule(String ruleName, Layer layer, Layer layer2, double k) {
this.ruleName = ruleName;
this.layer = layer;
this.layer2 = layer2;
this.k = k;
}
public DistanceRule clone() {
try {
return (DistanceRule)super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
private void writeXml(Writer writer) {
writer.b(XmlKeyword.rule);
writer.a("ruleName", ruleName);
if (layer != null) {
writer.a("layer", layer.name);
if (layer2 != null)
writer.a("layer2", layer2.name);
}
if (k != 1)
writer.a("k", k);
writer.e();
}
private double getLambda(DistanceContext context) {
return context.getRule(ruleName)*k;
}
}
public static class RuleSet implements Serializable {
public final String name;
public final Map<String,Map<Layer,Distance>> layerRules = new LinkedHashMap<String,Map<Layer,Distance>>();
private RuleSet(String name) {
this.name = name;
}
public Map<Layer,Distance> newLayerRule(String ruleName) {
if (ruleName == null)
throw new NullPointerException();
if (layerRules.containsKey(ruleName))
throw new IllegalArgumentException("Duplicate LayerRule " + ruleName);
Map<Layer,Distance> layerRule = new LinkedHashMap<Layer,Distance>();
layerRules.put(ruleName, layerRule);
return layerRule;
}
}
public static class Foundry implements Serializable {
public String name;
public final Map<String,String> layerGds = new LinkedHashMap<String,String>();
public final List<DRCTemplate> rules = new ArrayList<DRCTemplate>();
}
private XmlParam() {}
private static enum XmlKeyword {
technology,
shortName(true),
description(true),
numMetals,
scale,
defaultFoundry,
minResistance,
minCapacitance,
layer,
display3D,
cifLayer,
skillLayer,
parasitics,
pureLayerNode,
arcProto,
oldName(true),
wipable,
curvable,
special,
notUsed,
skipSizeInPalette,
extended(true),
fixedAngle(true),
angleIncrement(true),
antennaRatio(true),
elibWidthOffset(true),
arcLayer,
arcPin,
primitiveNode,
//oldName(true),
shrinkArcs,
square,
canBeZeroSize,
wipes,
lockable,
edgeSelect,
// skipSizeInPalette,
// notUsed,
lowVt,
highVt,
nativeBit,
od18,
od25,
od33,
diskOffset,
defaultWidth,
defaultHeight,
nodeBase,
nodeLayer,
box,
multicutbox,
serpbox,
lambdaBox,
points,
techPoint,
primitivePort,
portAngle,
portTopology(true),
// techPoint,
portArc(true),
polygonal,
serpTrans,
specialValue(true),
minSizeRule,
spiceTemplate,
spiceHeader,
spiceLine,
displayStyle,
transparentLayer,
r(true),
g(true),
b(true),
transparentColor,
opaqueColor,
patternedOnDisplay(true),
patternedOnPrinter(true),
pattern(true),
outlined(true),
opacity(true),
foreground(true),
menuPalette,
menuBox,
menuArc(true),
menuNode(true),
menuCell,
menuText(true),
menuNodeInst,
menuNodeText,
lambda(true),
rule,
ruleSet,
layerRule,
Foundry,
layerGds,
LayerRule,
LayersRule,
NodeLayersRule,
NodeRule;
private final boolean hasText;
private XmlKeyword() {
hasText = false;
};
private XmlKeyword(boolean hasText) {
this.hasText = hasText;
}
};
private static final HashMap<String,XmlKeyword> xmlKeywords = new HashMap<String,XmlKeyword>();
static {
for (XmlKeyword k: XmlKeyword.class.getEnumConstants())
xmlKeywords.put(k.name(), k);
}
private static Schema schema = null;
private static synchronized void loadTechnologySchema() throws SAXException {
if (schema != null) return;
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
URL technologySchemaUrl = Technology.class.getResource("xml/TechnologyParam.xsd");
if (technologySchemaUrl != null)
schema = schemaFactory.newSchema(technologySchemaUrl);
else
{
System.err.println("Schema file TechnologyParam.xsd, working without XML schema");
System.out.println("Schema file TechnologyParam.xsd, working without XML schema");
}
}
public static Technology parseTechnology(URL fileURL) {
// System.out.println("Memory usage " + Main.getMemoryUsage() + " bytes");
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
try {
if (schema == null)
loadTechnologySchema();
factory.setSchema(schema);
// factory.setValidating(true);
// System.out.println("Memory usage " + Main.getMemoryUsage() + " bytes");
// create the parser
long startTime = System.currentTimeMillis();
SAXParser parser = factory.newSAXParser();
URLConnection urlCon = fileURL.openConnection();
InputStream inputStream = urlCon.getInputStream();
XMLReader handler = new XMLReader();
parser.parse(inputStream, handler);
if (Job.getDebug())
{
long stopTime = System.currentTimeMillis();
System.out.println("Loading technology " + fileURL + " ... " + (stopTime - startTime) + " msec");
}
return handler.tech;
} catch (SAXParseException e) {
String msg = "Error parsing Xml technology:\n" +
e.getMessage() + "\n" +
" Line " + e.getLineNumber() + " column " + e.getColumnNumber() + " of " + fileURL;
msg = msg.replaceAll("\"http://electric.sun.com/Technology\":", "");
System.out.println(msg);
Job.getUserInterface().showErrorMessage(msg, "Error parsing Xml technology");
} catch (Exception e) {
String msg = "Error loading Xml technology " + fileURL + " :\n"
+ e.getMessage() + "\n";
System.out.println(msg);
Job.getUserInterface().showErrorMessage(msg, "Error loading Xml technology");
}
return null;
}
/**
* Method to parse a string of XML that describes the component menu in a Technology Editing context.
* Normal parsing of XML returns objects in the Xml class, but
* this method returns objects in a given Technology-Editor world.
* @param xml the XML string
* @param nodes the PrimitiveNode objects describing nodes in the technology.
* @param arcs the ArcProto objects describing arcs in the technology.
* @return the MenuPalette describing the component menu.
*/
public static MenuPalette parseComponentMenuXMLTechEdit(String xml, List<PrimitiveNode> nodes, List<ArcProto> arcs)
{
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
try
{
SAXParser parser = factory.newSAXParser();
InputSource is = new InputSource(new StringReader(xml));
XMLReader handler = new XMLReader(nodes, arcs);
parser.parse(is, handler);
return handler.tech.menuPalette;
} catch (Exception e)
{
System.out.println("Error parsing XML component menu data");
e.printStackTrace();
}
return null;
}
private static class XMLReader extends DefaultHandler {
private static boolean DEBUG = false;
private Locator locator;
private Technology tech = new Technology();
private Layer curLayer;
private ArcProto curArc;
private PrimitiveNode curNode;
private NodeLayer curNodeLayer;
private PrimitivePort curPort;
private int curSpecialValueIndex;
private ArrayList<Object> curMenuBox;
private MenuNodeInst curMenuNodeInst;
private MenuCell curMenuCell;
private Distance curDistance;
private SpiceHeader curSpiceHeader;
private DisplayStyle curDisplayStyle;
private int curTransparent = 0;
private int curR;
private int curG;
private int curB;
private LayerDisplayStyle curLayerDisplayStyle;
private boolean patternedOnDisplay;
private boolean patternedOnPrinter;
private final int[] pattern = new int[16];
private int curPatternIndex;
private EGraphics.Outline outline;
private double opacity;
private boolean foreground;
private RuleSet curRuleSet;
private Map<Layer,Distance> curLayerRule;
private Foundry curFoundry;
private boolean acceptCharacters;
private StringBuilder charBuffer = new StringBuilder();
private Attributes attributes;
XMLReader() {
}
XMLReader(List<PrimitiveNode> nodes, List<ArcProto> arcs)
{
for(ArcProto xap : arcs)
tech.arcs.add(xap);
for(PrimitiveNode xnp : nodes)
tech.nodes.add(xnp);
}
private void beginCharacters() {
assert !acceptCharacters;
acceptCharacters = true;
assert charBuffer.length() == 0;
}
private String endCharacters() {
assert acceptCharacters;
String s = charBuffer.toString();
charBuffer.setLength(0);
acceptCharacters = false;
return s;
}
////////////////////////////////////////////////////////////////////
// Default implementation of the EntityResolver interface.
////////////////////////////////////////////////////////////////////
/**
* Resolve an external entity.
*
* <p>Always return null, so that the parser will use the system
* identifier provided in the XML document. This method implements
* the SAX default behaviour: application writers can override it
* in a subclass to do special translations such as catalog lookups
* or URI redirection.</p>
*
* @param publicId The public identifier, or null if none is
* available.
* @param systemId The system identifier provided in the XML
* document.
* @return The new input source, or null to require the
* default behaviour.
* @exception java.io.IOException If there is an error setting
* up the new input source.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.EntityResolver#resolveEntity
*/
public InputSource resolveEntity(String publicId, String systemId)
throws IOException, SAXException {
return null;
}
////////////////////////////////////////////////////////////////////
// Default implementation of DTDHandler interface.
////////////////////////////////////////////////////////////////////
/**
* Receive notification of a notation declaration.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass if they wish to keep track of the notations
* declared in a document.</p>
*
* @param name The notation name.
* @param publicId The notation public identifier, or null if not
* available.
* @param systemId The notation system identifier.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.DTDHandler#notationDecl
*/
public void notationDecl(String name, String publicId, String systemId)
throws SAXException {
// int x = 0;
}
/**
* Receive notification of an unparsed entity declaration.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to keep track of the unparsed entities
* declared in a document.</p>
*
* @param name The entity name.
* @param publicId The entity public identifier, or null if not
* available.
* @param systemId The entity system identifier.
* @param notationName The name of the associated notation.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.DTDHandler#unparsedEntityDecl
*/
public void unparsedEntityDecl(String name, String publicId,
String systemId, String notationName)
throws SAXException {
// int x = 0;
}
////////////////////////////////////////////////////////////////////
// Default implementation of ContentHandler interface.
////////////////////////////////////////////////////////////////////
/**
* Receive a Locator object for document events.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass if they wish to store the locator for use
* with other document events.</p>
*
* @param locator A locator for all SAX document events.
* @see org.xml.sax.ContentHandler#setDocumentLocator
* @see org.xml.sax.Locator
*/
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
private void printLocator() {
System.out.println("publicId=" + locator.getPublicId() + " systemId=" + locator.getSystemId() +
" line=" + locator.getLineNumber() + " column=" + locator.getColumnNumber());
}
/**
* Receive notification of the beginning of the document.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the beginning
* of a document (such as allocating the root node of a tree or
* creating an output file).</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startDocument
*/
public void startDocument()
throws SAXException {
if (DEBUG) {
System.out.println("startDocument");
}
}
/**
* Receive notification of the end of the document.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end
* of a document (such as finalising a tree or closing an output
* file).</p>
*
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endDocument
*/
public void endDocument()
throws SAXException {
if (DEBUG) {
System.out.println("endDocument");
}
}
/**
* Receive notification of the start of a Namespace mapping.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the start of
* each Namespace prefix scope (such as storing the prefix mapping).</p>
*
* @param prefix The Namespace prefix being declared.
* @param uri The Namespace URI mapped to the prefix.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startPrefixMapping
*/
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
if (DEBUG) {
System.out.println("startPrefixMapping prefix=" + prefix + " uri=" + uri);
}
}
/**
* Receive notification of the end of a Namespace mapping.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each prefix mapping.</p>
*
* @param prefix The Namespace prefix being declared.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endPrefixMapping
*/
public void endPrefixMapping(String prefix)
throws SAXException {
if (DEBUG) {
System.out.println("endPrefixMapping prefix=" + prefix);
}
}
/**
* Receive notification of the start of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the start of
* each element (such as allocating a new tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @param attributes The attributes attached to the element. If
* there are no attributes, it shall be an empty
* Attributes object.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startElement
*/
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
boolean dump = false;
XmlKeyword key = xmlKeywords.get(localName);
// System.out.print("<" + key.name());
this.attributes = attributes;
switch (key) {
case technology:
tech.techName = a("name");
tech.className = a_("class");
// dump = true;
break;
case numMetals:
tech.minNumMetals = Integer.parseInt(a("min"));
tech.maxNumMetals = Integer.parseInt(a("max"));
tech.defaultNumMetals = Integer.parseInt(a("default"));
break;
case scale:
tech.scaleValue = Double.parseDouble(a("value"));
tech.scaleRelevant = Boolean.parseBoolean(a("relevant"));
break;
case defaultFoundry:
tech.defaultFoundry = a("value");
break;
case minResistance:
tech.minResistance = Double.parseDouble(a("value"));
break;
case minCapacitance:
tech.minCapacitance = Double.parseDouble(a("value"));
break;
case layer:
if (curDisplayStyle != null) {
curLayerDisplayStyle = curDisplayStyle.newLayer(tech.findLayer(a("name")));
curTransparent = 0;
curR = curG = curB = 0;
patternedOnDisplay = false;
patternedOnPrinter = false;
Arrays.fill(pattern, 0);
curPatternIndex = 0;
// EGraphics.Outline outline = null;
} else if (curLayerRule != null) {
curDistance = new Distance();
Distance old = curLayerRule.put(tech.findLayer(a("name")), curDistance);
if (old == null)
throw new IllegalArgumentException("Duplicate layer " + a("name"));
} else {
curLayer = tech.newLayer(a("name"));
curLayer.function = com.sun.electric.technology.Layer.Function.valueOf(a("fun"));
String extraFunStr = a_("extraFun");
if (extraFunStr != null) {
if (extraFunStr.equals("depletion_heavy"))
curLayer.extraFunction = com.sun.electric.technology.Layer.Function.DEPLETION|com.sun.electric.technology.Layer.Function.HEAVY;
else if (extraFunStr.equals("depletion_light"))
curLayer.extraFunction = com.sun.electric.technology.Layer.Function.DEPLETION|com.sun.electric.technology.Layer.Function.LIGHT;
else if (extraFunStr.equals("enhancement_heavy"))
curLayer.extraFunction = com.sun.electric.technology.Layer.Function.ENHANCEMENT|com.sun.electric.technology.Layer.Function.HEAVY;
else if (extraFunStr.equals("enhancement_light"))
curLayer.extraFunction = com.sun.electric.technology.Layer.Function.ENHANCEMENT|com.sun.electric.technology.Layer.Function.LIGHT;
else
curLayer.extraFunction = com.sun.electric.technology.Layer.Function.parseExtraName(extraFunStr);
}
}
break;
case cifLayer:
curLayer.cif = a("cif");
break;
case skillLayer:
curLayer.skill = a("skill");
break;
case parasitics:
curLayer.resistance = Double.parseDouble(a("resistance"));
curLayer.capacitance = Double.parseDouble(a("capacitance"));
curLayer.edgeCapacitance = Double.parseDouble(a("edgeCapacitance"));
break;
case pureLayerNode:
curLayer.pureLayerNode = new PureLayerNode();
curLayer.pureLayerNode.name = a("name");
String styleStr = a_("style");
curLayer.pureLayerNode.style = styleStr != null ? Type.valueOf(styleStr) : Type.FILLED;
curLayer.pureLayerNode.port = a("port");
break;
case arcProto:
curArc = new ArcProto();
curArc.name = a("name");
curArc.function = com.sun.electric.technology.ArcProto.Function.valueOf(a("fun"));
break;
case wipable:
curArc.wipable = true;
break;
case curvable:
curArc.curvable = true;
break;
case special:
curArc.special = true;
break;
case notUsed:
if (curArc != null)
curArc.notUsed = true;
if (curNode != null)
curNode.notUsed = true;
break;
case skipSizeInPalette:
if (curArc != null)
curArc.skipSizeInPalette = true;
if (curNode != null)
curNode.skipSizeInPalette = true;
break;
case arcLayer:
ArcLayer arcLay = new ArcLayer();
arcLay.layer = a("layer");
curDistance = arcLay.extend;
arcLay.style = Type.valueOf(a("style"));
curArc.arcLayers.add(arcLay);
break;
case arcPin:
curArc.arcPin = new ArcPin();
curArc.arcPin.name = a("name");
curArc.arcPin.portName = a("port");
curArc.arcPin.elibSize = Double.valueOf(a("elibSize"));
break;
case primitiveNode:
curNode = new PrimitiveNode();
curNode.name = a("name");
curNode.function = com.sun.electric.technology.PrimitiveNode.Function.valueOf(a("fun"));
break;
case shrinkArcs:
curNode.shrinkArcs = true;
break;
case square:
curNode.square = true;
break;
case canBeZeroSize:
curNode.canBeZeroSize = true;
break;
case wipes:
curNode.wipes = true;
break;
case lockable:
curNode.lockable = true;
break;
case edgeSelect:
curNode.edgeSelect = true;
break;
case lowVt:
curNode.lowVt = true;
break;
case highVt:
curNode.highVt = true;
break;
case nativeBit:
curNode.nativeBit = true;
break;
case od18:
curNode.od18 = true;
break;
case od25:
curNode.od25 = true;
break;
case od33:
curNode.od33 = true;
break;
case diskOffset:
curNode.diskOffset = EPoint.fromLambda(Double.parseDouble(a("x")), Double.parseDouble(a("y")));
break;
case defaultWidth:
curDistance = curNode.defaultWidth;
break;
case defaultHeight:
curDistance = curNode.defaultHeight;
break;
case nodeBase:
double lx = Double.parseDouble(a("lx"));
double hx = Double.parseDouble(a("hx"));
double ly = Double.parseDouble(a("ly"));
double hy = Double.parseDouble(a("hy"));
curNode.nodeBase = ERectangle.fromLambda(lx, ly, hx - lx, hy - ly);
break;
case nodeLayer:
curNodeLayer = new NodeLayer();
curNodeLayer.layer = a("layer");
curNodeLayer.style = Type.valueOf(a("style"));
String portNum = a_("portNum");
if (portNum != null)
curNodeLayer.portNum = Integer.parseInt(portNum);
String electrical = a_("electrical");
if (electrical != null) {
if (Boolean.parseBoolean(electrical))
curNodeLayer.inElectricalLayers = true;
else
curNodeLayer.inLayers = true;
} else {
curNodeLayer.inElectricalLayers = curNodeLayer.inLayers = true;
}
break;
case box:
if (curNodeLayer != null) {
curNodeLayer.representation = com.sun.electric.technology.Technology.NodeLayer.BOX;
curNodeLayer.lx.k = da_("klx", -1);
curNodeLayer.hx.k = da_("khx", 1);
curNodeLayer.ly.k = da_("kly", -1);
curNodeLayer.hy.k = da_("khy", 1);
}
if (curPort != null) {
curPort.lx.k = da_("klx", -1);
curPort.hx.k = da_("khx", 1);
curPort.ly.k = da_("kly", -1);
curPort.hy.k = da_("khy", 1);
}
break;
case points:
curNodeLayer.representation = com.sun.electric.technology.Technology.NodeLayer.POINTS;
break;
case multicutbox:
curNodeLayer.representation = com.sun.electric.technology.Technology.NodeLayer.MULTICUTBOX;
curNodeLayer.lx.k = da_("klx", -1);
curNodeLayer.hx.k = da_("khx", 1);
curNodeLayer.ly.k = da_("kly", -1);
curNodeLayer.hy.k = da_("khy", 1);
curNodeLayer.sizeRule = a("sizeRule");
curNodeLayer.sepRule = a("sepRule");
curNodeLayer.sepRule2D = a_("sepRule2D");
break;
case serpbox:
curNodeLayer.representation = com.sun.electric.technology.Technology.NodeLayer.BOX;
curNodeLayer.lx.k = da_("klx", -1);
curNodeLayer.hx.k = da_("khx", 1);
curNodeLayer.ly.k = da_("kly", -1);
curNodeLayer.hy.k = da_("khy", 1);
curNodeLayer.lWidth = Double.parseDouble(a("lWidth"));
curNodeLayer.rWidth = Double.parseDouble(a("rWidth"));
curNodeLayer.tExtent = Double.parseDouble(a("tExtent"));
curNodeLayer.bExtent = Double.parseDouble(a("bExtent"));
break;
case lambdaBox:
if (curNodeLayer != null) {
curNodeLayer.lx.addLambda(Double.parseDouble(a("klx")));
curNodeLayer.hx.addLambda(Double.parseDouble(a("khx")));
curNodeLayer.ly.addLambda(Double.parseDouble(a("kly")));
curNodeLayer.hy.addLambda(Double.parseDouble(a("khy")));
}
if (curPort != null) {
curPort.lx.addLambda(Double.parseDouble(a("klx")));
curPort.hx.addLambda(Double.parseDouble(a("khx")));
curPort.ly.addLambda(Double.parseDouble(a("kly")));
curPort.hy.addLambda(Double.parseDouble(a("khy")));
}
break;
case techPoint:
double xm = Double.parseDouble(a("xm"));
double xa = Double.parseDouble(a("xa"));
double ym = Double.parseDouble(a("ym"));
double ya = Double.parseDouble(a("ya"));
TechPoint p = new TechPoint(new EdgeH(xm, xa), new EdgeV(ym, ya));
if (curNodeLayer != null)
curNodeLayer.techPoints.add(p);
break;
case primitivePort:
curPort = new PrimitivePort();
curPort.name = a("name");
break;
case portAngle:
curPort.portAngle = Integer.parseInt(a("primary"));
curPort.portRange = Integer.parseInt(a("range"));
break;
case polygonal:
curNode.specialType = com.sun.electric.technology.PrimitiveNode.POLYGONAL;
break;
case serpTrans:
curNode.specialType = com.sun.electric.technology.PrimitiveNode.SERPTRANS;
curNode.specialValues = new double[6];
curSpecialValueIndex = 0;
break;
case minSizeRule:
curNode.nodeSizeRule = new NodeSizeRule();
curNode.nodeSizeRule.width = Double.parseDouble(a("width"));
curNode.nodeSizeRule.height = Double.parseDouble(a("height"));
curNode.nodeSizeRule.rule = a("rule");
break;
case spiceTemplate:
curNode.spiceTemplate = a("value");
break;
case spiceHeader:
curSpiceHeader = new SpiceHeader();
curSpiceHeader.level = Integer.parseInt(a("level"));
tech.spiceHeaders.add(curSpiceHeader);
break;
case spiceLine:
curSpiceHeader.spiceLines.add(a("line"));
break;
case displayStyle:
curDisplayStyle = new DisplayStyle();
curDisplayStyle.name = a("name");
tech.displayStyles.add(curDisplayStyle);
break;
case transparentLayer:
curTransparent = Integer.parseInt(a("transparent"));
curR = curG = curB = 0;
break;
case transparentColor:
curTransparent = Integer.parseInt(a("transparent"));
if (curTransparent > 0) {
Color color = curDisplayStyle.transparentLayers.get(curTransparent - 1);
curR = color.getRed();
curG = color.getGreen();
curB = color.getBlue();
}
break;
case opaqueColor:
curR = Integer.parseInt(a("r"));
curG = Integer.parseInt(a("g"));
curB = Integer.parseInt(a("b"));
break;
case display3D:
curLayerDisplayStyle.mode3D = a("mode");
curLayerDisplayStyle.factor3D = Double.parseDouble(a("factor"));
break;
case menuPalette:
tech.menuPalette = new MenuPalette();
tech.menuPalette.numColumns = Integer.parseInt(a("numColumns"));
break;
case menuBox:
curMenuBox = new ArrayList<Object>();
tech.menuPalette.menuBoxes.add(curMenuBox);
break;
case menuCell:
curMenuCell = new MenuCell();
curMenuCell.cellName = a("cellName");
break;
case menuNodeInst:
curMenuNodeInst = new MenuNodeInst();
curMenuNodeInst.protoName = a("protoName");
curMenuNodeInst.function = com.sun.electric.technology.PrimitiveNode.Function.valueOf(a("function"));
String rotField = a_("rotation");
if (rotField != null) curMenuNodeInst.rotation = Integer.parseInt(rotField);
break;
case menuNodeText:
curMenuNodeInst.text = a("text");
curMenuNodeInst.fontSize = Double.parseDouble(a("size"));
break;
case rule:
String kStr = a_("k");
Layer layer = null;
Layer layer2 = null;
String layerStr = a_("layer");
if (layerStr != null) {
layer = tech.findLayer(layerStr);
assert layer != null;
}
String layerStr2 = layerStr != null ? a_("layer2") : null;
if (layerStr2 != null) {
layer2 = tech.findLayer(layerStr2);
assert layer2 != null;
}
curDistance.addRule(a("ruleName"), layer, layer2, kStr != null ? Double.valueOf(kStr) : 1);
break;
case ruleSet:
curRuleSet = tech.newRuleSet(a("ruleName"));
break;
case layerRule:
curLayerRule = curRuleSet.newLayerRule(a("ruleName"));
break;
case Foundry:
curFoundry = new Foundry();
curFoundry.name = a("name");
tech.foundries.add(curFoundry);
break;
case layerGds:
curFoundry.layerGds.put(a("layer"), a("gds"));
break;
case LayerRule:
case LayersRule:
case NodeLayersRule:
case NodeRule:
DRCTemplate.parseXmlElement(curFoundry.rules, key.name(), attributes, localName);
break;
default:
assert key.hasText;
beginCharacters();
// System.out.print(">");
return;
}
assert !key.hasText;
// System.out.println(">");
if (dump) {
System.out.println("startElement uri=" + uri + " localName=" + localName + " qName=" + qName);
for (int i = 0; i < attributes.getLength(); i++) {
System.out.println("\tattribute " + i + " uri=" + attributes.getURI(i) +
" localName=" + attributes.getLocalName(i) + " QName=" + attributes.getQName(i) +
" type=" + attributes.getType(i) + " value=<" + attributes.getValue(i) + ">");
}
}
}
private double da_(String attrName, double defaultValue) {
String s = a_(attrName);
return s != null ? Double.parseDouble(s) : defaultValue;
}
private String a(String attrName) {
String v = attributes.getValue(attrName);
// System.out.print(" " + attrName + "=\"" + v + "\"");
return v;
}
private String a_(String attrName) {
String v = attributes.getValue(attrName);
if (v == null) return null;
// System.out.print(" " + attrName + "=\"" + v + "\"");
return v;
}
/**
* Receive notification of the end of an element.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions at the end of
* each element (such as finalising a tree node or writing
* output to a file).</p>
*
* @param uri The Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace
* processing is not being performed.
* @param localName The local name (without prefix), or the
* empty string if Namespace processing is not being
* performed.
* @param qName The qualified name (with prefix), or the
* empty string if qualified names are not available.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endElement
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
XmlKeyword key = xmlKeywords.get(localName);
if (key.hasText) {
String text = endCharacters();
// System.out.println(text + "</" + localName + ">");
switch (key) {
case shortName:
tech.shortTechName = text;
break;
case description:
tech.description = text;
break;
case oldName:
if (curLayer != null)
curLayer.pureLayerNode.oldName = text;
if (curArc != null)
curArc.oldName = text;
if (curNode != null)
curNode.oldName = text;
break;
case extended:
curArc.extended = Boolean.parseBoolean(text);
break;
case fixedAngle:
curArc.fixedAngle = Boolean.parseBoolean(text);
break;
case wipable:
curArc.wipable = Boolean.parseBoolean(text);
break;
case angleIncrement:
curArc.angleIncrement = Integer.parseInt(text);
break;
case antennaRatio:
curArc.antennaRatio = Double.parseDouble(text);
break;
case elibWidthOffset:
curArc.elibWidthOffset = Double.parseDouble(text);
break;
case portTopology:
curPort.portTopology = Integer.parseInt(text);
break;
case portArc:
if (curLayer != null && curLayer.pureLayerNode != null)
curLayer.pureLayerNode.portArcs.add(text);
if (curArc != null && curArc.arcPin != null)
curArc.arcPin.portArcs.add(text);
if (curPort != null)
curPort.portArcs.add(text);
break;
case specialValue:
curNode.specialValues[curSpecialValueIndex++] = Double.parseDouble(text);
break;
case r:
curR = Integer.parseInt(text);
break;
case g:
curG = Integer.parseInt(text);
break;
case b:
curB = Integer.parseInt(text);
break;
case patternedOnDisplay:
patternedOnDisplay = Boolean.parseBoolean(text);
break;
case patternedOnPrinter:
patternedOnPrinter = Boolean.parseBoolean(text);
break;
case pattern:
int p = 0;
assert text.length() == 16;
for (int j = 0; j < text.length(); j++) {
if (text.charAt(text.length() - j - 1) != ' ')
p |= (1 << j);
}
pattern[curPatternIndex++] = p;
break;
case outlined:
outline = EGraphics.Outline.valueOf(text);
break;
case opacity:
opacity = Double.parseDouble(text);
break;
case foreground:
foreground = Boolean.parseBoolean(text);
break;
case menuArc:
curMenuBox.add(tech.findArc(text));
break;
case menuNode:
curMenuBox.add(tech.findNode(text));
break;
case menuText:
curMenuBox.add(text);
break;
case lambda:
curDistance.addLambda(Double.parseDouble(text));
break;
default:
assert false;
}
return;
}
// System.out.println("</" + localName + ">");
switch (key) {
case technology:
break;
case layer:
if (curDisplayStyle != null) {
assert curPatternIndex == pattern.length;
curLayerDisplayStyle.desc = new EGraphics(patternedOnDisplay, patternedOnPrinter, outline, curTransparent,
curR, curG, curB, opacity, foreground, pattern.clone());
curLayerDisplayStyle = null;
} else if (curLayerRule != null) {
curDistance = null;
} else {
curLayer = null;
}
break;
case arcProto:
tech.arcs.add(curArc);
curArc = null;
break;
case primitiveNode:
tech.nodes.add(curNode);
curNode = null;
break;
case nodeLayer:
curNode.nodeLayers.add(curNodeLayer);
curNodeLayer = null;
break;
case primitivePort:
curNode.ports.add(curPort);
curPort = null;
break;
case menuNodeInst:
curMenuBox.add(curMenuNodeInst);
curMenuNodeInst = null;
break;
case displayStyle:
curDisplayStyle = null;
break;
case transparentLayer:
while (curTransparent > curDisplayStyle.transparentLayers.size())
curDisplayStyle.transparentLayers.add(null);
Color oldColor = curDisplayStyle.transparentLayers.set(curTransparent - 1, new Color(curR, curG, curB));
assert oldColor == null;
break;
case menuCell:
curMenuBox.add("LOADCELL " + curMenuCell.cellName);
// curMenuBox.add(curMenuCell);
curMenuCell = null;
break;
case ruleSet:
curRuleSet = null;
break;
case layerRule:
curLayerRule = null;
break;
case numMetals:
case scale:
case defaultFoundry:
case minResistance:
case minCapacitance:
case cifLayer:
case skillLayer:
case parasitics:
case pureLayerNode:
case wipable:
case curvable:
case special:
case notUsed:
case skipSizeInPalette:
case arcLayer:
case arcPin:
case shrinkArcs:
case square:
case canBeZeroSize:
case wipes:
case lockable:
case edgeSelect:
case lowVt:
case highVt:
case nativeBit:
case od18:
case od25:
case od33:
case diskOffset:
case defaultWidth:
case defaultHeight:
case nodeBase:
case box:
case points:
case multicutbox:
case serpbox:
case lambdaBox:
case techPoint:
case portAngle:
case polygonal:
case serpTrans:
case minSizeRule:
case spiceHeader:
case spiceLine:
case spiceTemplate:
case transparentColor:
case opaqueColor:
case display3D:
case menuPalette:
case menuBox:
case menuNodeText:
case rule:
case Foundry:
case layerGds:
case LayerRule:
case LayersRule:
case NodeLayersRule:
case NodeRule:
break;
default:
assert false;
}
}
/**
* Receive notification of character data inside an element.
*
* <p>By default, do nothing. Application writers may override this
* method to take specific actions for each chunk of character data
* (such as adding the data to a node or buffer, or printing it to
* a file).</p>
*
* @param ch The characters.
* @param start The start position in the character array.
* @param length The number of characters to use from the
* character array.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#characters
*/
public void characters(char ch[], int start, int length)
throws SAXException {
if (acceptCharacters) {
charBuffer.append(ch, start, length);
} else {
boolean nonBlank = false;
for (int i = 0; i < length; i++) {
char c = ch[start + i];
nonBlank = nonBlank || c != ' ' && c != '\n';
}
if (nonBlank) {
System.out.print("characters size=" + ch.length + " start=" + start + " length=" + length + " {");
for (int i = 0; i < length; i++)
System.out.print(ch[start + i]);
System.out.println("}");
}
}
}
/**
* Receive notification of ignorable whitespace in element content.
*
* <p>By default, do nothing. Application writers may override this
* method to take specific actions for each chunk of ignorable
* whitespace (such as adding data to a node or buffer, or printing
* it to a file).</p>
*
* @param ch The whitespace characters.
* @param start The start position in the character array.
* @param length The number of characters to use from the
* character array.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#ignorableWhitespace
*/
public void ignorableWhitespace(char ch[], int start, int length)
throws SAXException {
// int x = 0;
}
/**
* Receive notification of a processing instruction.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions for each
* processing instruction, such as setting status variables or
* invoking other methods.</p>
*
* @param target The processing instruction target.
* @param data The processing instruction data, or null if
* none is supplied.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#processingInstruction
*/
public void processingInstruction(String target, String data)
throws SAXException {
// int x = 0;
}
/**
* Receive notification of a skipped entity.
*
* <p>By default, do nothing. Application writers may override this
* method in a subclass to take specific actions for each
* processing instruction, such as setting status variables or
* invoking other methods.</p>
*
* @param name The name of the skipped entity.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#processingInstruction
*/
public void skippedEntity(String name)
throws SAXException {
// int x = 0;
}
////////////////////////////////////////////////////////////////////
// Default implementation of the ErrorHandler interface.
////////////////////////////////////////////////////////////////////
/**
* Receive notification of a parser warning.
*
* <p>The default implementation does nothing. Application writers
* may override this method in a subclass to take specific actions
* for each warning, such as inserting the message in a log file or
* printing it to the console.</p>
*
* @param e The warning information encoded as an exception.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ErrorHandler#warning
* @see org.xml.sax.SAXParseException
*/
public void warning(SAXParseException e)
throws SAXException {
System.out.println("warning publicId=" + e.getPublicId() + " systemId=" + e.getSystemId() +
" line=" + e.getLineNumber() + " column=" + e.getColumnNumber() + " message=" + e.getMessage() + " exception=" + e.getException());
}
/**
* Receive notification of a recoverable parser error.
*
* <p>The default implementation does nothing. Application writers
* may override this method in a subclass to take specific actions
* for each error, such as inserting the message in a log file or
* printing it to the console.</p>
*
* @param e The error information encoded as an exception.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ErrorHandler#warning
* @see org.xml.sax.SAXParseException
*/
public void error(SAXParseException e)
throws SAXException {
// System.out.println("error publicId=" + e.getPublicId() + " systemId=" + e.getSystemId() +
// " line=" + e.getLineNumber() + " column=" + e.getColumnNumber() + " message=" + e.getMessage() + " exception=" + e.getException());
throw e;
}
/**
* Report a fatal XML parsing error.
*
* <p>The default implementation throws a SAXParseException.
* Application writers may override this method in a subclass if
* they need to take specific actions for each fatal error (such as
* collecting all of the errors into a single report): in any case,
* the application must stop all regular processing when this
* method is invoked, since the document is no longer reliable, and
* the parser may no longer report parsing events.</p>
*
* @param e The error information encoded as an exception.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ErrorHandler#fatalError
* @see org.xml.sax.SAXParseException
*/
public void fatalError(SAXParseException e)
throws SAXException {
// System.out.println("fatal error publicId=" + e.getPublicId() + " systemId=" + e.getSystemId() +
// " line=" + e.getLineNumber() + " column=" + e.getColumnNumber() + " message=" + e.getMessage() + " exception=" + e.getException());
throw e;
}
}
private static class Writer {
private static final int INDENT_WIDTH = 4;
protected final PrintWriter out;
private int indent;
protected boolean indentEmitted;
private Writer(PrintWriter out) {
this.out = out;
}
private void writeTechnology(Technology t) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
header();
pl("");
out.println("<!--");
pl(" *");
pl(" * Electric(tm) VLSI Design System");
pl(" *");
pl(" * File: " + t.techName + ".xml");
pl(" * " + t.techName + " technology description");
pl(" * Generated automatically from a library");
pl(" *");
pl(" * Copyright (c) " + cal.get(Calendar.YEAR) + " Sun Microsystems and Static Free Software");
pl(" *");
pl(" * Electric(tm) is free software; you can redistribute it and/or modify");
pl(" * it under the terms of the GNU General Public License as published by");
pl(" * the Free Software Foundation; either version 3 of the License, or");
pl(" * (at your option) any later version.");
pl(" *");
pl(" * Electric(tm) is distributed in the hope that it will be useful,");
pl(" * but WITHOUT ANY WARRANTY; without even the implied warranty of");
pl(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the");
pl(" * GNU General Public License for more details.");
pl(" *");
pl(" * You should have received a copy of the GNU General Public License");
pl(" * along with Electric(tm); see the file COPYING. If not, write to");
pl(" * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,");
pl(" * Boston, Mass 02111-1307, USA.");
pl(" */");
out.println("-->");
l();
b(XmlKeyword.technology); a("name", t.techName); a("class", t.className); l();
a("xmlns", "http://electric.sun.com/Technology"); l();
a("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); l();
a("xsi:schemaLocation", "http://electric.sun.com/Technology ../../technology/xml/TechnologyParam.xsd"); cl();
l();
bcpel(XmlKeyword.shortName, t.shortTechName);
bcpel(XmlKeyword.description, t.description);
b(XmlKeyword.numMetals); a("min", t.minNumMetals); a("max", t.maxNumMetals); a("default", t.defaultNumMetals); el();
b(XmlKeyword.scale); a("value", t.scaleValue); a("relevant", t.scaleRelevant); el();
b(XmlKeyword.defaultFoundry); a("value", t.defaultFoundry); el();
b(XmlKeyword.minResistance); a("value", t.minResistance); el();
b(XmlKeyword.minCapacitance); a("value", t.minCapacitance); el();
// printlnAttribute(" gateLengthSubtraction", gi.gateShrinkage);
// printlnAttribute(" gateInclusion", gi.includeGateInResistance);
// printlnAttribute(" groundNetInclusion", gi.includeGround);
l();
comment("**************************************** LAYERS ****************************************");
for (Layer li: t.layers.values()) {
writeXml(li);
}
comment("******************** ARCS ********************");
for (ArcProto ai: t.arcs) {
writeXml(ai);
l();
}
comment("******************** NODES ********************");
for (PrimitiveNode ni: t.nodes) {
writeXml(ni);
l();
}
for (SpiceHeader spiceHeader: t.spiceHeaders)
writeSpiceHeaderXml(spiceHeader);
for (DisplayStyle displayStyle: t.displayStyles)
writeDisplayStyleXml(displayStyle);
writeMenuPaletteXml(t.menuPalette);
for (RuleSet ruleSet: t.ruleSets.values())
writeXml(ruleSet);
for (Foundry foundry: t.foundries)
writeFoundryXml(foundry);
el(XmlKeyword.technology);
}
private void writeXml(Layer li) {
String funString = null;
int funExtra = li.extraFunction;
if (funExtra != 0) {
final int deplEnhMask = com.sun.electric.technology.Layer.Function.DEPLETION|com.sun.electric.technology.Layer.Function.ENHANCEMENT;
if ((funExtra&deplEnhMask) != 0) {
funString = com.sun.electric.technology.Layer.Function.getExtraName(funExtra&(deplEnhMask));
funExtra &= ~deplEnhMask;
if (funExtra != 0)
funString += "_" + com.sun.electric.technology.Layer.Function.getExtraName(funExtra);
} else {
funString = com.sun.electric.technology.Layer.Function.getExtraName(funExtra);
}
}
b(XmlKeyword.layer); a("name", li.name); a("fun", li.function.name()); a("extraFun", funString); cl();
if (li.cif != null && li.cif.length() > 0) {
b(XmlKeyword.cifLayer); a("cif", li.cif); el();
}
if (li.skill != null && li.skill.length() > 0) {
b(XmlKeyword.skillLayer); a("skill", li.skill); el();
}
// write the SPICE information
if (li.resistance != 0 || li.capacitance != 0 || li.edgeCapacitance != 0) {
b(XmlKeyword.parasitics); a("resistance", li.resistance); a("capacitance", li.capacitance); a("edgeCapacitance", li.edgeCapacitance); el();
}
if (li.pureLayerNode != null) {
String nodeName = li.pureLayerNode.name;
Type style = li.pureLayerNode.style;
String styleStr = style == Type.FILLED ? null : style.name();
String portName = li.pureLayerNode.port;
b(XmlKeyword.pureLayerNode); a("name", nodeName); a("style", styleStr); a("port", portName);
if (li.pureLayerNode.oldName == null && li.pureLayerNode.portArcs.isEmpty()) {
el();
} else {
cl();
bcpel(XmlKeyword.oldName, li.pureLayerNode.oldName);
for (String portArc: li.pureLayerNode.portArcs)
bcpel(XmlKeyword.portArc, portArc);
el(XmlKeyword.pureLayerNode);
}
}
el(XmlKeyword.layer);
l();
}
private void writeXml(ArcProto ai) {
b(XmlKeyword.arcProto); a("name", ai.name); a("fun", ai.function.getConstantName()); cl();
bcpel(XmlKeyword.oldName, ai.oldName);
if (ai.wipable)
bel(XmlKeyword.wipable);
if (ai.curvable)
bel(XmlKeyword.curvable);
if (ai.special)
bel(XmlKeyword.special);
if (ai.notUsed)
bel(XmlKeyword.notUsed);
if (ai.skipSizeInPalette)
bel(XmlKeyword.skipSizeInPalette);
bcpel(XmlKeyword.extended, ai.extended);
bcpel(XmlKeyword.fixedAngle, ai.fixedAngle);
bcpel(XmlKeyword.angleIncrement, ai.angleIncrement);
if (ai.antennaRatio != 0)
bcpel(XmlKeyword.antennaRatio, ai.antennaRatio);
if (ai.elibWidthOffset != 0)
bcpel(XmlKeyword.elibWidthOffset, ai.elibWidthOffset);
for (ArcLayer al: ai.arcLayers) {
String style = al.style == Type.FILLED ? "FILLED" : "CLOSED";
b(XmlKeyword.arcLayer); a("layer", al.layer); a("style", style);
if (al.extend.isEmpty()) {
el();
} else {
cl();
writeDistance(al.extend);
el(XmlKeyword.arcLayer);
}
}
if (ai.arcPin != null) {
b(XmlKeyword.arcPin); a("name", ai.arcPin.name); a("port", ai.arcPin.portName); a("elibSize", ai.arcPin.elibSize);
if (ai.arcPin.portArcs.isEmpty()) {
el();
} else {
cl();
for (String portArc: ai.arcPin.portArcs)
bcpel(XmlKeyword.portArc, portArc);
el(XmlKeyword.arcPin);
}
}
el(XmlKeyword.arcProto);
}
private void writeXml(PrimitiveNode ni) {
b(XmlKeyword.primitiveNode); a("name", ni.name); a("fun", ni.function.name()); cl();
bcpel(XmlKeyword.oldName, ni.oldName);
if (ni.shrinkArcs)
bel(XmlKeyword.shrinkArcs);
if (ni.square)
bel(XmlKeyword.square);
if (ni.canBeZeroSize)
bel(XmlKeyword.canBeZeroSize);
if (ni.wipes)
bel(XmlKeyword.wipes);
if (ni.lockable)
bel(XmlKeyword.lockable);
if (ni.edgeSelect)
bel(XmlKeyword.edgeSelect);
if (ni.skipSizeInPalette)
bel(XmlKeyword.skipSizeInPalette);
if (ni.notUsed)
bel(XmlKeyword.notUsed);
if (ni.lowVt)
bel(XmlKeyword.lowVt);
if (ni.highVt)
bel(XmlKeyword.highVt);
if (ni.nativeBit)
bel(XmlKeyword.nativeBit);
if (ni.od18)
bel(XmlKeyword.od18);
if (ni.od25)
bel(XmlKeyword.od25);
if (ni.od33)
bel(XmlKeyword.od33);
if (ni.diskOffset != null) {
b(XmlKeyword.diskOffset); a("x", ni.diskOffset.getLambdaX()); a("y", ni.diskOffset.getLambdaY()); el();
}
if (!ni.defaultWidth.isEmpty()) {
bcl(XmlKeyword.defaultWidth);
writeDistance(ni.defaultWidth);
el(XmlKeyword.defaultWidth);
}
if (!ni.defaultHeight.isEmpty()) {
bcl(XmlKeyword.defaultHeight);
writeDistance(ni.defaultHeight);
el(XmlKeyword.defaultHeight);
}
if (ni.nodeBase != null) {
double lx = ni.nodeBase.getLambdaMinX();
double hx = ni.nodeBase.getLambdaMaxX();
double ly = ni.nodeBase.getLambdaMinY();
double hy = ni.nodeBase.getLambdaMaxY();
b(XmlKeyword.nodeBase); a("lx", lx); a("hx", hx); a("ly", ly); a("hy", hy); el();
}
for(int j=0; j<ni.nodeLayers.size(); j++) {
NodeLayer nl = ni.nodeLayers.get(j);
b(XmlKeyword.nodeLayer); a("layer", nl.layer); a("style", nl.style.name());
if (nl.portNum != 0) a("portNum", Integer.valueOf(nl.portNum));
if (!(nl.inLayers && nl.inElectricalLayers))
a("electrical", nl.inElectricalLayers);
cl();
switch (nl.representation) {
case com.sun.electric.technology.Technology.NodeLayer.BOX:
if (ni.specialType == com.sun.electric.technology.PrimitiveNode.SERPTRANS) {
writeBox(XmlKeyword.serpbox, nl.lx, nl.hx, nl.ly, nl.hy);
a("lWidth", nl.lWidth); a("rWidth", nl.rWidth); a("tExtent", nl.tExtent); a("bExtent", nl.bExtent); cl();
writeLambdaBox(nl.lx, nl.hx, nl.ly, nl.hy);
el(XmlKeyword.serpbox);
} else {
writeBox(XmlKeyword.box, nl.lx, nl.hx, nl.ly, nl.hy); cl();
writeLambdaBox(nl.lx, nl.hx, nl.ly, nl.hy);
el(XmlKeyword.box);
}
break;
case com.sun.electric.technology.Technology.NodeLayer.POINTS:
b(XmlKeyword.points); el();
break;
case com.sun.electric.technology.Technology.NodeLayer.MULTICUTBOX:
writeBox(XmlKeyword.multicutbox, nl.lx, nl.hx, nl.ly, nl.hy);
a("sizeRule", nl.sizeRule); a("sepRule", nl.sepRule); a("sepRule2D", nl.sepRule2D);
if (nl.lx.isEmpty() && nl.hx.isEmpty() && nl.ly.isEmpty() && nl.hy.isEmpty()) {
el();
} else {
cl();
writeLambdaBox(nl.lx, nl.hx, nl.ly, nl.hy);
el(XmlKeyword.multicutbox);
}
break;
}
for (TechPoint tp: nl.techPoints) {
double xm = tp.getX().getMultiplier();
double xa = tp.getX().getAdder();
double ym = tp.getY().getMultiplier();
double ya = tp.getY().getAdder();
b(XmlKeyword.techPoint); a("xm", xm); a("xa", xa); a("ym", ym); a("ya", ya); el();
}
el(XmlKeyword.nodeLayer);
}
for (int j = 0; j < ni.ports.size(); j++) {
PrimitivePort pd = ni.ports.get(j);
b(XmlKeyword.primitivePort); a("name", pd.name); cl();
b(XmlKeyword.portAngle); a("primary", pd.portAngle); a("range", pd.portRange); el();
bcpel(XmlKeyword.portTopology, pd.portTopology);
writeBox(XmlKeyword.box, pd.lx, pd.hx, pd.ly, pd.hy); cl();
writeLambdaBox(pd.lx, pd.hx, pd.ly, pd.hy);
el(XmlKeyword.box);
for (String portArc: pd.portArcs)
bcpel(XmlKeyword.portArc, portArc);
el(XmlKeyword.primitivePort);
}
switch (ni.specialType) {
case com.sun.electric.technology.PrimitiveNode.POLYGONAL:
bel(XmlKeyword.polygonal);
break;
case com.sun.electric.technology.PrimitiveNode.SERPTRANS:
b(XmlKeyword.serpTrans); cl();
for (int i = 0; i < 6; i++) {
bcpel(XmlKeyword.specialValue, ni.specialValues[i]);
}
el(XmlKeyword.serpTrans);
break;
}
if (ni.nodeSizeRule != null) {
NodeSizeRule r = ni.nodeSizeRule;
b(XmlKeyword.minSizeRule); a("width", r.width); a("height", r.height); a("rule", r.rule); el();
}
if (ni.spiceTemplate != null)
{
b(XmlKeyword.spiceTemplate); a("value", ni.spiceTemplate); el();
}
el(XmlKeyword.primitiveNode);
}
private void writeDistance(Distance d) {
d.writeXml(this, true);
}
private void writeBox(XmlKeyword keyword, Distance lx, Distance hx, Distance ly, Distance hy) {
b(keyword);
if (lx.k != -1) a("klx", lx.k);
if (hx.k != 1) a("khx", hx.k);
if (ly.k != -1) a("kly", ly.k);
if (hy.k != 1) a("khy", hy.k);
}
private void writeLambdaBox(Distance lx, Distance hx, Distance ly, Distance hy) {
double lxv = lx.getLambda(EMPTY_CONTEXT);
double hxv = hx.getLambda(EMPTY_CONTEXT);
double lyv = ly.getLambda(EMPTY_CONTEXT);
double hyv = hy.getLambda(EMPTY_CONTEXT);
// if (lxv == 0 && hxv == 0 && lyv == 0 && hyv == 0) return;
b(XmlKeyword.lambdaBox); a("klx", lxv); a("khx", hxv); a("kly", lyv); a("khy", hyv); el();
}
private void writeSpiceHeaderXml(SpiceHeader spiceHeader) {
b(XmlKeyword.spiceHeader); a("level", spiceHeader.level); cl();
for (String line: spiceHeader.spiceLines) {
b(XmlKeyword.spiceLine); a("line", line); el();
}
el(XmlKeyword.spiceHeader);
l();
}
private void writeDisplayStyleXml(DisplayStyle displayStyle) {
b(XmlKeyword.displayStyle); a("name", displayStyle.name); cl();
if (displayStyle.transparentLayers.size() != 0) {
comment("Transparent layers");
for (int i = 0; i < displayStyle.transparentLayers.size(); i++) {
Color color = displayStyle.transparentLayers.get(i);
b(XmlKeyword.transparentLayer); a("transparent", i + 1); cl();
bcpel(XmlKeyword.r, color.getRed());
bcpel(XmlKeyword.g, color.getGreen());
bcpel(XmlKeyword.b, color.getBlue());
el(XmlKeyword.transparentLayer);
}
l();
}
for (LayerDisplayStyle l: displayStyle.layerStyles.values()) {
b(XmlKeyword.layer); a("name", l.layer.name); cl();
EGraphics desc = l.desc;
if (desc.getTransparentLayer() > 0) {
b(XmlKeyword.transparentColor); a("transparent", desc.getTransparentLayer()); el();
} else {
Color color = desc.getColor();
b(XmlKeyword.opaqueColor); a("r", color.getRed()); a("g", color.getGreen()); a("b", color.getBlue()); el();
}
bcpel(XmlKeyword.patternedOnDisplay, desc.isPatternedOnDisplay());
bcpel(XmlKeyword.patternedOnPrinter, desc.isPatternedOnPrinter());
int [] pattern = desc.getPattern();
for(int j=0; j<16; j++) {
String p = "";
for(int k=0; k<16; k++)
p += (pattern[j] & (1 << (15-k))) != 0 ? 'X' : ' ';
bcpel(XmlKeyword.pattern, p);
}
if (desc.getOutlined() != null)
bcpel(XmlKeyword.outlined, desc.getOutlined().getConstName());
bcpel(XmlKeyword.opacity, desc.getOpacity());
bcpel(XmlKeyword.foreground, desc.getForeground());
// write the 3D information
if (l.mode3D != null) {
b(XmlKeyword.display3D); a("mode", l.mode3D); a("factor", l.factor3D); el();
}
el(XmlKeyword.layer);
}
el(XmlKeyword.displayStyle);
l();
}
public void writeMenuPaletteXml(MenuPalette menuPalette) {
if (menuPalette == null) return;
b(XmlKeyword.menuPalette); a("numColumns", menuPalette.numColumns); cl();
for (int i = 0; i < menuPalette.menuBoxes.size(); i++) {
if (i % menuPalette.numColumns == 0)
l();
writeMenuBoxXml(menuPalette.menuBoxes.get(i));
}
l();
el(XmlKeyword.menuPalette);
l();
}
private void writeMenuBoxXml(List<Object> list) {
b(XmlKeyword.menuBox);
if (list.size() == 0) {
el();
return;
}
cl();
for (Object o: list) {
if (o instanceof ArcProto) {
bcpel(XmlKeyword.menuArc, ((ArcProto)o).name);
} else if (o instanceof PrimitiveNode) {
bcpel(XmlKeyword.menuNode, ((PrimitiveNode)o).name);
} else if (o instanceof MenuCell) {
MenuCell cell = (MenuCell)o;
b(XmlKeyword.menuCell); a("cellName", cell.cellName); el();
} else if (o instanceof MenuNodeInst) {
MenuNodeInst ni = (MenuNodeInst)o;
b(XmlKeyword.menuNodeInst); a("protoName", ni.protoName); a("function", ni.function.name());
if (ni.rotation != 0) a("rotation", ni.rotation);
if (ni.text == null) {
el();
} else {
cl();
b(XmlKeyword.menuNodeText); a("text", ni.text); a("size", ni.fontSize); el();
el(XmlKeyword.menuNodeInst);
}
} else {
if (o == null) bel(XmlKeyword.menuText); else
bcpel(XmlKeyword.menuText, o);
}
}
el(XmlKeyword.menuBox);
}
private void writeXml(RuleSet ruleSet) {
b(XmlKeyword.ruleSet); a("name", ruleSet.name); cl();
for (Map.Entry<String,Map<Layer,Distance>> e: ruleSet.layerRules.entrySet())
writeLayerRuleXml(e.getKey(), e.getValue());
el(XmlKeyword.ruleSet);
l();
}
private void writeLayerRuleXml(String ruleName, Map<Layer,Distance> sizes) {
if (sizes.isEmpty()) return;
b(XmlKeyword.layerRule); a("ruleName", ruleName); cl();
int maxNameLength = 0;
for (Layer l: sizes.keySet())
maxNameLength = Math.max(maxNameLength, l.name.length());
for (Map.Entry<Layer,Distance> e: sizes.entrySet()) {
String layerName = e.getKey().name;
Distance d = e.getValue();
b(XmlKeyword.layer); a("name", layerName); c();
s(maxNameLength - layerName.length());
d.writeXml(this, false);
el(XmlKeyword.layer);
}
el(XmlKeyword.layerRule);
}
private void writeFoundryXml(Foundry foundry) {
b(XmlKeyword.Foundry); a("name", foundry.name); cl();
l();
for (Map.Entry<String,String> e: foundry.layerGds.entrySet()) {
b(XmlKeyword.layerGds); a("layer", e.getKey()); a("gds", e.getValue()); el();
}
l();
for (DRCTemplate rule: foundry.rules)
DRCTemplate.exportDRCRule(out, rule);
el(XmlKeyword.Foundry);
}
private void header() {
checkIndent();
out.print("<?xml"); a("version", "1.0"); a("encoding", "UTF-8"); out.println("?>");
}
private void comment(String s) {
checkIndent();
out.print("<!-- "); p(s); out.print(" -->"); l();
}
/**
* Print attribute.
*/
private void a(String name, Object value) {
checkIndent();
if (value == null) return;
out.print(" " + name + "=\"");
p(value.toString());
out.print("\"");
}
private void bcpe(XmlKeyword key, Object v) {
if (v == null) return;
b(key); c(); p(v.toString()); e(key);
}
private void bcpel(XmlKeyword key, Object v) {
if (v == null) return;
b(key); c(); p(v.toString()); el(key);
}
private void bcl(XmlKeyword key) {
b(key); cl();
}
private void bel(XmlKeyword key) {
b(key); el();
}
/**
* Print text with replacement of special chars.
*/
private void pl(String s) {
checkIndent();
p(s); l();
}
/**
* Print text with replacement of special chars.
*/
protected void p(String s) {
assert indentEmitted;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '<':
out.print("<");
break;
case '>':
out.print(">");
break;
case '&':
out.print("&");
break;
case '\'':
out.print("'");
break;
case '"':
out.print("quot;");
break;
default:
out.print(c);
}
}
}
/**
* Print element name, and indent.
*/
private void b(XmlKeyword key) {
checkIndent();
out.print('<');
out.print(key.name());
indent += INDENT_WIDTH;
}
private void cl() {
assert indentEmitted;
out.print('>');
l();
}
private void c() {
assert indentEmitted;
out.print('>');
}
private void el() {
e(); l();
}
private void el(XmlKeyword key) {
e(key); l();
}
private void e() {
assert indentEmitted;
out.print("/>");
indent -= INDENT_WIDTH;
}
private void e(XmlKeyword key) {
indent -= INDENT_WIDTH;
checkIndent();
out.print("</");
out.print(key.name());
out.print(">");
}
protected void checkIndent() {
if (indentEmitted) return;
s(indent);
indentEmitted = true;
}
protected void s(int numSpaces) {
for (int i = 0; i < numSpaces; i++)
out.print(' ');
}
/**
* Print new line.
*/
protected void l() {
out.println();
indentEmitted = false;
}
}
public static DistanceContext EMPTY_CONTEXT = new DistanceContext() {
public double getRule(String ruleName) {
throw new UnsupportedOperationException();
}
};
/**
* Class to write the XML without multiple lines and indentation.
* Useful when the XML is to be a single string.
*/
private static class OneLineWriter extends Writer
{
private OneLineWriter(PrintWriter out)
{
super(out);
}
/**
* Print text without replacement of special chars.
*/
@Override
protected void p(String s)
{
for (int i = 0; i < s.length(); i++)
out.print(s.charAt(i));
}
@Override
protected void checkIndent() { indentEmitted = true; }
/**
* Do not print new line.
*/
@Override
protected void l() { indentEmitted = false; }
}
}