All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.electric.technology.Xml Maven / Gradle / Ivy

/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Xml.java
 *
 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
 *
 * 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;

import com.sun.electric.database.geometry.EGraphics;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.Poly;
import com.sun.electric.technology.Technology.TechPoint;
import com.sun.electric.tool.Job;
import com.sun.electric.util.math.DBMath;

import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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.*;

import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.stream.StreamSource;
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 Xml {

    /** Default Logical effort gate capacitance. */
    public static final double DEFAULT_LE_GATECAP = 0.4;
    /** Default Logical effort wire ratio. */
    public static final double DEFAULT_LE_WIRERATIO = 0.16;
    /** Default Logical effort diff alpha. */
    public static final double DEFAULT_LE_DIFFALPHA = 0.7;

    public static class Technology implements Serializable {

        public String techName;
        public String className;
        public String shortTechName;
        public String description;
        public final List versions = new ArrayList();
        public int minNumMetals;
        public int maxNumMetals;
        public int defaultNumMetals;
        public double scaleValue;
        public double resolutionValue; // min resolution value allowed by the foundry
        public boolean scaleRelevant;
        public String defaultFoundry;
        public double minResistance;
        public double minCapacitance;
        public double leGateCapacitance = DEFAULT_LE_GATECAP;
        public double leWireRatio = DEFAULT_LE_WIRERATIO;
        public double leDiffAlpha = DEFAULT_LE_DIFFALPHA;
        public final List transparentLayers = new ArrayList();
        public final List layers = new ArrayList();
        public final List arcs = new ArrayList();
        public final List nodeGroups = new ArrayList();
        private final List pureLayerNodes = new ArrayList();
        public final List spiceHeaders = new ArrayList();
        public MenuPalette menuPalette;
        public final List foundries = new ArrayList();

        public Layer findLayer(String name) {
            for (Layer layer : layers) {
                if (layer.name.equals(name)) {
                    return layer;
                }
            }
            return null;
        }

        public Collection getLayerNames() {
            List l = new ArrayList();
            for (Layer layer : layers) {
                l.add(layer.name);
            }
            return l;
        }

        public ArcProto findArc(String name) {
            for (ArcProto arc : arcs) {
                if (arc.name.equals(name)) {
                    return arc;
                }
            }
            return null;
        }

        public PrimitiveNodeGroup findNodeGroup(String name) {
            for (PrimitiveNodeGroup nodeGroup : nodeGroups) {
                for (PrimitiveNode n : nodeGroup.nodes) {
                    if (n.name.equals(name)) {
                        return nodeGroup;
                    }
                }
            }
            return null;
        }

        public PrimitiveNode findNode(String name) {
            for (PrimitiveNodeGroup nodeGroup : nodeGroups) {
                for (PrimitiveNode n : nodeGroup.nodes) {
                    if (n.name.equals(name)) {
                        return n;
                    }
                }
            }
            for (PrimitiveNode n : pureLayerNodes) {
                if (n.name.equals(name)) {
                    return n;
                }
            }
            return null;
        }

        public Collection getNodeNames() {
            List l = new ArrayList();
            for (PrimitiveNodeGroup nodeGroup : nodeGroups) {
                for (PrimitiveNode n : nodeGroup.nodes) {
                    l.add(n.name);
                }
            }
            return l;
        }

        /**
         * Method to find the first PrimitiveNode which would have the given arc
         */
        public PrimitiveNode findPinNode(String arc) {
            for (PrimitiveNodeGroup nodeGroup : nodeGroups) {
                boolean foundPort = false;
                for (PrimitivePort p : nodeGroup.ports) {
                    if (p.portArcs.contains(arc)) {
                        foundPort = true;
                        break;
                    }
                }
                if (foundPort) // now checking if there is a pin associated with the arc
                {
                    for (PrimitiveNode n : nodeGroup.nodes) {
                        if (n.function.isPin()) {
                            return n;
                        }
                    }
                }
            }
            return null;
        }

        public void writeXml(String fileName) {
            writeXml(fileName, true, null);
        }

        public void writeXml(String fileName, boolean includeDateAndVersion, String copyrightMessage) {
            writeXml(fileName, includeDateAndVersion, copyrightMessage, null);
        }

        public void writeXml(String fileName, boolean includeDateAndVersion, String copyrightMessage,
                Map> additionalAttributes) {
            try {
                PrintWriter out = new PrintWriter(fileName);
                Writer writer = new Writer(out);
                writer.writeTechnology(this, includeDateAndVersion, copyrightMessage, additionalAttributes);
                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 Technology deepClone() {
            try {
                ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(byteStream);
                out.writeObject(this);
                out.flush();
                byte[] serializedXml = byteStream.toByteArray();
                ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(serializedXml));
                Xml.Technology clone = (Xml.Technology) in.readObject();
                in.close();
                return clone;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    public static class Version implements Serializable {

        public int techVersion;
        public com.sun.electric.database.text.Version electricVersion;
    }

    public static class Layer implements Serializable {

        public String name;
        public com.sun.electric.technology.Layer.Function function;
        public int extraFunction;
        public EGraphics desc;
        public double thick3D;
        public double height3D;
        public String cif;
        public String skill;
        public double resistance;
        public double capacitance;
        public double edgeCapacitance;
        public PureLayerNode pureLayerNode;
    }

    public static class PureLayerNode implements Serializable {

        public String name;
        public String oldName;
        public Poly.Type style;
        public String port;
        public final Distance size = new Distance();
        public final List portArcs = new ArrayList();
    }

    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 final Map diskOffset = new TreeMap();
        public final Distance defaultWidth = new Distance();
        public boolean extended;
        public boolean fixedAngle;
        public int angleIncrement;
        public double antennaRatio;
        public final List arcLayers = new ArrayList();
    }

    public static class ArcLayer implements Serializable {

        public String layer;
        public final Distance extend = new Distance();
        public Poly.Type style;
    }

    public static class PrimitiveNode implements Serializable {

        public String name;
        public com.sun.electric.technology.PrimitiveNode.Function function;
        public String oldName;
        public boolean lowVt;
        public boolean highVt;
        public boolean nativeBit;
        public boolean od18;
        public boolean od25;
        public boolean od33;
    }

    public static class PrimitiveNodeGroup implements Serializable {

        public boolean isSingleton;
        public final List nodes = new ArrayList();
        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 final Map diskOffset = new TreeMap();
        public final Distance defaultWidth = new Distance();
        public final Distance defaultHeight = new Distance();
        public final Distance baseLX = new Distance();
        public final Distance baseHX = new Distance();
        public final Distance baseLY = new Distance();
        public final Distance baseHY = new Distance();
        public ProtectionType protection;
        public final List nodeLayers = new ArrayList();
        public final List ports = new ArrayList();
        public int specialType;
        public double[] specialValues;
        public NodeSizeRule nodeSizeRule;
        public String spiceTemplate;
    }

    public enum ProtectionType {

        both, left, right, none;
    }

    public static class NodeLayer implements Serializable {

        public String layer;
        public BitSet inNodes;
        public Poly.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 techPoints = new ArrayList();
        public double sizex, sizey, sep1d, sep2d;
        public double lWidth, rWidth, tExtent, bExtent;
        private String message;

        /**
         * Unofficial method for use in builtin technologies
         */
        public String getMessage() {
            return message;
        }
        private double relSize;

        /**
         * Unofficial method for use in builtin technologies
         */
        public double getRelSize() {
            return relSize;
        }
    }

    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 portArcs = new ArrayList();
    }

    public static class SpiceHeader implements Serializable {

        public int level;
        public final List spiceLines = new ArrayList();
    }

    public static class MenuPalette implements Serializable {

        public int numColumns;
        public List> menuBoxes = new ArrayList>();

        public String writeXml() {
            StringWriter sw = new StringWriter();
            PrintWriter out = new PrintWriter(sw);
            Xml.OneLineWriter writer = new Xml.OneLineWriter(out);
            writer.writeMenuPaletteXml(this);
            out.close();
            return sw.getBuffer().toString();
        }
    }

    public static class MenuNodeInst implements Serializable {

        /** the name of the prototype in the menu */
        public String protoName;
        /** the function of the prototype */
        public com.sun.electric.technology.PrimitiveNode.Function function;
        /** tech bits */
        public int techBits;
        /** label to draw in the menu entry (may be null) */
        public String text;
        /** the rotation of the node in the menu entry */
        public int rotation;
    }

    public static class Distance implements Serializable {

        public double k;
        public double value;

        public void addLambda(double lambdaValue) {
            value += lambdaValue;
        }
    }

    public static class Foundry implements Serializable {

        public String name;
        public final Map layerGds = new LinkedHashMap();
        public final List rules = new ArrayList();
    }

    private Xml() {
    }

    private static enum XmlKeyword {

        technology,
        shortName(true),
        description(true),
        version,
        numMetals,
        scale,
        resolution,
        defaultFoundry,
        minResistance,
        minCapacitance,
        logicalEffort,
        transparentLayer,
        r(true),
        g(true),
        b(true),
        layer,
        transparentColor,
        opaqueColor,
        patternedOnDisplay(true),
        patternedOnPrinter(true),
        pattern(true),
        outlined(true),
        opacity(true),
        foreground(true),
        display3D,
        cifLayer,
        skillLayer,
        parasitics,
        pureLayerNode,
        arcProto,
        oldName(true),
        wipable,
        curvable,
        special,
        notUsed,
        skipSizeInPalette,
        extended(true),
        fixedAngle(true),
        angleIncrement(true),
        antennaRatio(true),
        diskOffset,
        defaultWidth,
        arcLayer,
        primitiveNodeGroup,
        inNodes,
        primitiveNode,
        //oldName(true),
        shrinkArcs,
        square,
        canBeZeroSize,
        wipes,
        lockable,
        edgeSelect,
        //        skipSizeInPalette,
        //        notUsed,
        lowVt,
        highVt,
        nativeBit,
        od18,
        od25,
        od33,
        //       defaultWidth,
        defaultHeight,
        nodeBase,
        sizeOffset,
        nodeLayer,
        box,
        multicutbox,
        serpbox,
        lambdaBox,
        points,
        techPoint,
        primitivePort,
        portAngle,
        portTopology(true),
        //        techPoint,
        portArc(true),
        polygonal,
        serpTrans,
        specialValue(true),
        // Protection layer for transistors
        protection,
        //        location(true),
        minSizeRule,
        spiceTemplate,
        spiceHeader,
        spiceLine,
        menuPalette,
        menuBox,
        menuArc(true),
        menuNode(true),
        menuText(true),
        menuNodeInst,
        menuNodeText,
        lambda(true),
        Foundry,
        layerGds,
        LayerRule,
        LayersRule,
        NodeLayersRule,
        NodeRule;
        private final boolean hasText;

        private XmlKeyword() {
            hasText = false;
        }

        ;
        private XmlKeyword(boolean hasText) {
            this.hasText = hasText;
        }
    };
    private static final Map xmlKeywords = new HashMap();

    static {
        for (XmlKeyword k : XmlKeyword.class.getEnumConstants()) {
            xmlKeywords.put(k.name(), k);
        }
    }
    private static Schema schema = null;

    private static synchronized void loadTechnologySchema() throws SAXException, IOException {
        if (schema != null) {
            return;
        }
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        URL technologySchemaUrl = Technology.class.getResource("Technology.xsd");
        if (technologySchemaUrl != null) {
            schema = schemaFactory.newSchema(new StreamSource(technologySchemaUrl.openStream()));
        } else {
            System.err.println("Schema file Technology.xsd, working without XML schema");
            System.out.println("Schema file Technology.xsd, working without XML schema");
        }
    }

    public static Technology parseTechnology(URL fileURL) {
        return parseTechnology(fileURL, true);
    }

    public static Technology parseTechnology(URL fileURL, boolean checkSchema) {
//        System.out.println("Memory usage " + Main.getMemoryUsage() + " bytes");
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);
        try {
            if (schema == null) {
                loadTechnologySchema();
            }
            if (checkSchema) {
                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");
        } catch (Error a) {
            String msg = "Assertion while loading Xml technology " + fileURL;
            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 nodeGroups the PrimitiveNodeGroup objects describing nodes in the technology.
     * @param arcs the ArcProto objects describing arcs in the technology.
     * @param pureLayerNodes the PrimitiveNode objects describing pure-layer nodes in the technology.
     * @return the MenuPalette describing the component menu.
     */
    public static MenuPalette parseComponentMenuXMLTechEdit(String xml, List nodeGroups, List arcs,
            List pureLayerNodes) {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setNamespaceAware(true);
        try {
            SAXParser parser = factory.newSAXParser();
            InputSource is = new InputSource(new StringReader(xml));
            XMLReader handler = new XMLReader(nodeGroups, arcs, pureLayerNodes);
            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 Xml.Technology tech = new Xml.Technology();
        private int curTransparent = 0;
        private int curR;
        private int curG;
        private int curB;
        private Layer curLayer;
        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 EGraphics.J3DTransparencyOption transparencyMode;
        private double transparencyFactor;
        private ArcProto curArc;
        private PrimitiveNodeGroup curNodeGroup;
        private boolean curNodeGroupHasNodeBase;
        private PrimitiveNode curNode;
        private NodeLayer curNodeLayer;
        private PrimitivePort curPort;
        private int curSpecialValueIndex;
        private ArrayList curMenuBox;
        private MenuNodeInst curMenuNodeInst;
        private Distance curDistance;
        private SpiceHeader curSpiceHeader;
        private Foundry curFoundry;
        private Collection curLayerNamesList;
        private Collection curNodeNamesList;
        private boolean acceptCharacters;
        private StringBuilder charBuffer = new StringBuilder();
        private Attributes attributes;

        XMLReader() {
        }

        XMLReader(List nodeGroups, List arcs, List pureLayerNodes) {
            tech.arcs.addAll(arcs);
            tech.nodeGroups.addAll(nodeGroups);
            tech.pureLayerNodes.addAll(pureLayerNodes);
        }

        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.
         *
         * 

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.

* * @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. * *

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.

* * @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. * *

By default, do nothing. Application writers may override this * method in a subclass to keep track of the unparsed entities * declared in a document.

* * @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. * *

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.

* * @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. * *

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).

* * @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. * *

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).

* * @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. * *

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).

* * @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. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions at the end of * each prefix mapping.

* * @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. * *

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).

* * @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"); if (tech.className != null) { int index = tech.className.indexOf("."); String realName = tech.className; while (index != -1) { realName = realName.substring(index + 1); index = realName.indexOf("."); } if (!realName.toLowerCase().equals(tech.techName.toLowerCase())) { System.out.println("Mismatch between techName '" + tech.techName + "' and className '" + realName + "' in the XML technology file."); } } // dump = true; break; case version: Version localVersion = new Version(); localVersion.techVersion = Integer.parseInt(a("tech")); localVersion.electricVersion = com.sun.electric.database.text.Version.parseVersion(a("electric")); tech.versions.add(localVersion); 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 resolution: tech.resolutionValue = Double.parseDouble(a("value")); // default is 0; 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 logicalEffort: tech.leGateCapacitance = Double.parseDouble(a("gateCapacitance")); tech.leWireRatio = Double.parseDouble(a("wireRatio")); tech.leDiffAlpha = Double.parseDouble(a("diffAlpha")); break; case transparentLayer: curTransparent = Integer.parseInt(a("transparent")); curR = curG = curB = 0; break; case layer: curLayer = new Layer(); curLayer.name = 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); } } curTransparent = 0; curR = curG = curB = 0; patternedOnDisplay = false; patternedOnPrinter = false; Arrays.fill(pattern, 0); curPatternIndex = 0; transparencyMode = EGraphics.DEFAULT_MODE; transparencyFactor = EGraphics.DEFAULT_FACTOR; // EGraphics.Outline outline = null; break; case transparentColor: curTransparent = Integer.parseInt(a("transparent")); if (curTransparent > 0) { Color color = tech.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: curLayer.thick3D = Double.parseDouble(a("thick")); curLayer.height3D = Double.parseDouble(a("height")); String modeStr = a_("mode"); if (modeStr != null) { transparencyMode = EGraphics.J3DTransparencyOption.valueOf(modeStr); } String factorStr = a_("factor"); if (factorStr != null) { transparencyFactor = Double.parseDouble(factorStr); } 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 ? Poly.Type.valueOf(styleStr) : Poly.Type.FILLED; curLayer.pureLayerNode.port = a("port"); curDistance = curLayer.pureLayerNode.size; Xml.PrimitiveNode n = new Xml.PrimitiveNode(); n.name = curLayer.pureLayerNode.name; n.function = com.sun.electric.technology.PrimitiveNode.Function.NODE; tech.pureLayerNodes.add(n); 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; } else if (curNodeGroup != null) { curNodeGroup.notUsed = true; } break; case skipSizeInPalette: if (curArc != null) { curArc.skipSizeInPalette = true; } else if (curNodeGroup != null) { curNodeGroup.skipSizeInPalette = true; } break; case diskOffset: if (curArc != null) { curArc.diskOffset.put(new Integer(Integer.parseInt(a("untilVersion"))), new Double(Double.parseDouble(a("width")))); } else if (curNodeGroup != null) { curNodeGroup.diskOffset.put(new Integer(Integer.parseInt(a("untilVersion"))), EPoint.fromLambda(Double.parseDouble(a("x")), Double.parseDouble(a("y")))); } break; case defaultWidth: if (curArc != null) { curDistance = curArc.defaultWidth; } else if (curNodeGroup != null) { curDistance = curNodeGroup.defaultWidth; } break; case arcLayer: ArcLayer arcLayer = new ArcLayer(); arcLayer.layer = a("layer"); curDistance = arcLayer.extend; arcLayer.style = Poly.Type.valueOf(a("style")); curArc.arcLayers.add(arcLayer); break; case primitiveNodeGroup: curNodeGroup = new PrimitiveNodeGroup(); curNodeGroupHasNodeBase = false; curNode = null; if (a_("name") != null) { System.out.println("Attribute 'name' in is deprecated"); } if (a_("fun") != null) { System.out.println("Attribute 'fun' in is deprecated"); } break; case inNodes: if (curNodeGroup.isSingleton) { throw new SAXException(" can be used only inside "); } curNodeLayer.inNodes = new BitSet(); break; case primitiveNode: if (curNodeLayer != null) { assert !curNodeGroup.isSingleton && curNode == null; String nodeName = a("name"); int i = 0; while (i < curNodeGroup.nodes.size() && !curNodeGroup.nodes.get(i).name.equals(nodeName)) { i++; } if (i >= curNodeGroup.nodes.size()) { throw new SAXException("No node " + nodeName + " in group"); } curNodeLayer.inNodes.set(i); } else if (curNodeGroup != null) { assert !curNodeGroup.isSingleton; curNode = new PrimitiveNode(); curNode.name = a("name"); curNode.function = com.sun.electric.technology.PrimitiveNode.Function.valueOf(a("fun")); curNodeGroup.nodes.add(curNode); } else { curNodeGroup = new PrimitiveNodeGroup(); curNodeGroupHasNodeBase = false; curNodeGroup.isSingleton = true; curNode = new PrimitiveNode(); curNode.name = a("name"); curNode.function = com.sun.electric.technology.PrimitiveNode.Function.valueOf(a("fun")); curNodeGroup.nodes.add(curNode); } break; case shrinkArcs: curNodeGroup.shrinkArcs = true; break; case square: curNodeGroup.square = true; break; case canBeZeroSize: curNodeGroup.canBeZeroSize = true; break; case wipes: curNodeGroup.wipes = true; break; case lockable: curNodeGroup.lockable = true; break; case edgeSelect: curNodeGroup.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 defaultHeight: curDistance = curNodeGroup.defaultHeight; break; case nodeBase: curNodeGroupHasNodeBase = true; break; case sizeOffset: curNodeGroup.baseLX.value = Double.parseDouble(a("lx")); curNodeGroup.baseHX.value = -Double.parseDouble(a("hx")); curNodeGroup.baseLY.value = Double.parseDouble(a("ly")); curNodeGroup.baseHY.value = -Double.parseDouble(a("hy")); break; case protection: curNodeGroup.protection = ProtectionType.valueOf(a("location")); break; case nodeLayer: curNodeLayer = new NodeLayer(); curNodeLayer.layer = a("layer"); if (tech.findLayer(curNodeLayer.layer) == null) { throw new SAXException("Error: cannot find layer '" + curNodeLayer.layer + "' in primitive node '" + curNode.name + "'. Skiping this NodeLayer"); } else { curNodeLayer.style = Poly.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; } // Unly for buildin technologies curNodeLayer.message = a_("message"); String relSize = a_("relSize"); if (relSize != null) { curNodeLayer.relSize = Double.parseDouble(relSize); } } 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); } else 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); } else { assert curNodeGroupHasNodeBase; curNodeGroup.baseLX.k = curNodeGroup.baseLY.k = -1; curNodeGroup.baseHX.k = curNodeGroup.baseHY.k = 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.sizex = Double.parseDouble(a("sizex")); curNodeLayer.sizey = Double.parseDouble(a("sizey")); curNodeLayer.sep1d = Double.parseDouble(a("sep1d")); curNodeLayer.sep2d = Double.parseDouble(a("sep2d")); 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.value = Double.parseDouble(a("klx")); curNodeLayer.hx.value = Double.parseDouble(a("khx")); curNodeLayer.ly.value = Double.parseDouble(a("kly")); curNodeLayer.hy.value = Double.parseDouble(a("khy")); } else if (curPort != null) { curPort.lx.value = Double.parseDouble(a("klx")); curPort.hx.value = Double.parseDouble(a("khx")); curPort.ly.value = Double.parseDouble(a("kly")); curPort.hy.value = Double.parseDouble(a("khy")); } else { assert curNodeGroupHasNodeBase; curNodeGroup.baseLX.value = Double.parseDouble(a("klx")); curNodeGroup.baseHX.value = Double.parseDouble(a("khx")); curNodeGroup.baseLY.value = Double.parseDouble(a("kly")); curNodeGroup.baseHY.value = 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: curNodeGroup.specialType = com.sun.electric.technology.PrimitiveNode.POLYGONAL; break; case serpTrans: curNodeGroup.specialType = com.sun.electric.technology.PrimitiveNode.SERPTRANS; curNodeGroup.specialValues = new double[6]; curSpecialValueIndex = 0; break; case minSizeRule: curNodeGroup.nodeSizeRule = new NodeSizeRule(); curNodeGroup.nodeSizeRule.width = Double.parseDouble(a("width")); curNodeGroup.nodeSizeRule.height = Double.parseDouble(a("height")); curNodeGroup.nodeSizeRule.rule = a("rule"); break; case spiceTemplate: curNodeGroup.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 menuPalette: tech.menuPalette = new MenuPalette(); tech.menuPalette.numColumns = Integer.parseInt(a("numColumns")); break; case menuBox: curMenuBox = new ArrayList(); tech.menuPalette.menuBoxes.add(curMenuBox); break; case menuNodeInst: curMenuNodeInst = new MenuNodeInst(); curMenuNodeInst.protoName = a("protoName"); if (tech.findNode(curMenuNodeInst.protoName) == null) { System.out.println("Warning: cannot find node '" + curMenuNodeInst.protoName + "' for component menu"); } curMenuNodeInst.function = com.sun.electric.technology.PrimitiveNode.Function.findType(a("function")); if (curMenuNodeInst.function == null) { System.out.println("Error: cannot find function '" + a("function") + "' for node '" + a("protoName" + "'")); } String techBits = a_("techBits"); if (techBits != null) { curMenuNodeInst.techBits = Integer.parseInt(techBits); } 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 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: if (curLayerNamesList == null) { curLayerNamesList = tech.getLayerNames(); } if (curNodeNamesList == null) { curNodeNamesList = tech.getNodeNames(); } if (!DRCTemplate.parseXmlElement(curFoundry.rules, curLayerNamesList, curNodeNamesList, key.name(), attributes, localName)) { System.out.println("Warning: cannot find layer name in DRC rule '" + key.name()); } 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. * *

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).

* * @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 + ""); switch (key) { case shortName: tech.shortTechName = text; break; case description: tech.description = 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 oldName: if (curLayer != null) { curLayer.pureLayerNode.oldName = text; } else if (curArc != null) { curArc.oldName = text; } else { 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 portTopology: curPort.portTopology = Integer.parseInt(text); break; case portArc: if (curLayer != null && curLayer.pureLayerNode != null) { curLayer.pureLayerNode.portArcs.add(text); } if (curPort != null) { curPort.portArcs.add(text); } break; case specialValue: curNodeGroup.specialValues[curSpecialValueIndex++] = Double.parseDouble(text); break; case menuArc: ArcProto ap = tech.findArc(text); if (ap == null) { System.out.println("Warning: cannot find arc '" + text + "' for component menu"); } else { curMenuBox.add(ap); } break; case menuNode: PrimitiveNode np = tech.findNode(text); if (np == null) { System.out.println("Warning: cannot find node '" + text + "' for component menu"); } else { curMenuBox.add(np); } break; case menuText: curMenuBox.add(text); break; case lambda: curDistance.addLambda(Double.parseDouble(text)); break; default: assert false; } return; } // System.out.println(""); switch (key) { case technology: break; case transparentLayer: while (curTransparent > tech.transparentLayers.size()) { tech.transparentLayers.add(null); } Color oldColor = tech.transparentLayers.set(curTransparent - 1, new Color(curR, curG, curB)); assert oldColor == null; break; case layer: assert curPatternIndex == pattern.length; curLayer.desc = new EGraphics(patternedOnDisplay, patternedOnPrinter, outline, curTransparent, curR, curG, curB, opacity, foreground, pattern.clone(), transparencyMode, transparencyFactor); assert tech.findLayer(curLayer.name) == null; tech.layers.add(curLayer); curLayer = null; break; case arcProto: tech.arcs.add(curArc); curArc = null; break; case primitiveNodeGroup: fixNodeBase(); tech.nodeGroups.add(curNodeGroup); curNodeGroup = null; curNode = null; break; case primitiveNode: if (curNodeGroup.isSingleton) { fixNodeBase(); tech.nodeGroups.add(curNodeGroup); curNodeGroup = null; curNode = null; } else if (curNodeLayer == null) { assert !curNodeGroup.isSingleton; curNode = null; } break; case nodeLayer: if (curNodeLayer != null) { curNodeGroup.nodeLayers.add(curNodeLayer); curNodeLayer = null; } break; case primitivePort: curNodeGroup.ports.add(curPort); curPort = null; break; case menuNodeInst: curMenuBox.add(curMenuNodeInst); curMenuNodeInst = null; break; case version: case spiceHeader: case numMetals: case scale: case resolution: case defaultFoundry: case minResistance: case minCapacitance: case logicalEffort: case transparentColor: case opaqueColor: case display3D: case cifLayer: case skillLayer: case parasitics: case pureLayerNode: case wipable: case curvable: case special: case notUsed: case skipSizeInPalette: case diskOffset: case defaultWidth: case arcLayer: case inNodes: 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 defaultHeight: case nodeBase: case sizeOffset: case protection: case box: case points: case multicutbox: case serpbox: case lambdaBox: case techPoint: case portAngle: case polygonal: case serpTrans: case minSizeRule: case spiceLine: case spiceTemplate: case menuPalette: case menuBox: case menuNodeText: case Foundry: case layerGds: case LayerRule: case LayersRule: case NodeLayersRule: case NodeRule: break; default: assert false; } } private void fixNodeBase() { if (curNodeGroupHasNodeBase) { return; } double lx, hx, ly, hy; if (curNodeGroup.nodeSizeRule != null) { hx = 0.5 * curNodeGroup.nodeSizeRule.width; lx = -hx; hy = 0.5 * curNodeGroup.nodeSizeRule.height; ly = -hy; } else { lx = Double.POSITIVE_INFINITY; hx = Double.NEGATIVE_INFINITY; ly = Double.POSITIVE_INFINITY; hy = Double.NEGATIVE_INFINITY; for (int i = 0; i < curNodeGroup.nodeLayers.size(); i++) { Xml.NodeLayer nl = curNodeGroup.nodeLayers.get(i); double x, y; if (nl.representation == com.sun.electric.technology.Technology.NodeLayer.BOX || nl.representation == com.sun.electric.technology.Technology.NodeLayer.MULTICUTBOX) { x = nl.lx.value; lx = Math.min(lx, x); hx = Math.max(hx, x); x = nl.hx.value; lx = Math.min(lx, x); hx = Math.max(hx, x); y = nl.ly.value; ly = Math.min(ly, y); hy = Math.max(hy, y); y = nl.hy.value; ly = Math.min(ly, y); hy = Math.max(hy, y); } else { for (com.sun.electric.technology.Technology.TechPoint p : nl.techPoints) { x = p.getX().getAdder().getLambda(); lx = Math.min(lx, x); hx = Math.max(hx, x); y = p.getY().getAdder().getLambda(); ly = Math.min(ly, y); hy = Math.max(hy, y); } } } } curNodeGroup.baseLX.value = DBMath.round(lx + curNodeGroup.baseLX.value); curNodeGroup.baseHX.value = DBMath.round(hx + curNodeGroup.baseHX.value); curNodeGroup.baseLY.value = DBMath.round(ly + curNodeGroup.baseLY.value); curNodeGroup.baseHY.value = DBMath.round(hy + curNodeGroup.baseHY.value); } /** * Receive notification of character data inside an element. * *

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).

* * @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' && c != '\t'; } 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. * *

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).

* * @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. * *

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.

* * @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. * *

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.

* * @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. * *

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.

* * @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. * *

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.

* * @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. * *

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.

* * @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(Xml.Technology t, boolean includeDateAndVersion, String copyrightMessage, Map> additionalAttributes) { Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); header(); 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/Technology.xsd"); cl(); l(); bcpel(XmlKeyword.shortName, t.shortTechName); bcpel(XmlKeyword.description, t.description); for (Version version : t.versions) { b(XmlKeyword.version); a("tech", version.techVersion); a("electric", version.electricVersion); el(); } 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", Boolean.valueOf(t.scaleRelevant)); el(); b(XmlKeyword.resolution); a("value", t.resolutionValue); 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(); if (t.leGateCapacitance != DEFAULT_LE_GATECAP || t.leWireRatio != DEFAULT_LE_WIRERATIO || t.leDiffAlpha != DEFAULT_LE_DIFFALPHA) { b(XmlKeyword.logicalEffort); a("gateCapacitance", t.leGateCapacitance); a("wireRatio", t.leWireRatio); a("diffAlpha", t.leDiffAlpha); el(); } // printlnAttribute(" gateLengthSubtraction", gi.gateShrinkage); // printlnAttribute(" gateInclusion", gi.includeGateInResistance); // printlnAttribute(" groundNetInclusion", gi.includeGround); l(); if (t.transparentLayers.size() != 0) { comment("Transparent layers"); for (int i = 0; i < t.transparentLayers.size(); i++) { Color color = t.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(); } comment("**************************************** LAYERS ****************************************"); for (Xml.Layer li : t.layers) { writeXml(li); } comment("******************** ARCS ********************"); for (Xml.ArcProto ai : t.arcs) { writeXml(ai); l(); } comment("******************** NODES ********************"); for (Xml.PrimitiveNodeGroup nodeGroup : t.nodeGroups) { writeXml(nodeGroup, additionalAttributes); l(); } for (Xml.SpiceHeader spiceHeader : t.spiceHeaders) { writeSpiceHeaderXml(spiceHeader); } writeMenuPaletteXml(t.menuPalette); for (Xml.Foundry foundry : t.foundries) { writeFoundryXml(foundry); } el(XmlKeyword.technology); } private void writeXml(Xml.Layer li) { EGraphics desc = li.desc; 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 (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, Boolean.valueOf(desc.isPatternedOnDisplay())); bcpel(XmlKeyword.patternedOnPrinter, Boolean.valueOf(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 (li.desc.getOutlined() != null) { bcpel(XmlKeyword.outlined, desc.getOutlined().getConstName()); } bcpel(XmlKeyword.opacity, desc.getOpacity()); bcpel(XmlKeyword.foreground, Boolean.valueOf(desc.getForeground())); // write the 3D information b(XmlKeyword.display3D); a("thick", li.thick3D); a("height", li.height3D); a("mode", li.desc.getTransparencyMode()); a("factor", li.desc.getTransparencyFactor()); el(); 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; Poly.Type style = li.pureLayerNode.style; String styleStr = style == Poly.Type.FILLED ? null : style.name(); String portName = li.pureLayerNode.port; b(XmlKeyword.pureLayerNode); a("name", nodeName); a("style", styleStr); a("port", portName); cl(); bcpel(XmlKeyword.oldName, li.pureLayerNode.oldName); bcpel(XmlKeyword.lambda, li.pureLayerNode.size.value); for (String portArc : li.pureLayerNode.portArcs) { bcpel(XmlKeyword.portArc, portArc); } el(XmlKeyword.pureLayerNode); } el(XmlKeyword.layer); l(); } private void writeXml(Xml.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, Boolean.valueOf(ai.extended)); bcpel(XmlKeyword.fixedAngle, Boolean.valueOf(ai.fixedAngle)); bcpel(XmlKeyword.angleIncrement, ai.angleIncrement); if (ai.antennaRatio != 0) { bcpel(XmlKeyword.antennaRatio, ai.antennaRatio); } for (Map.Entry e : ai.diskOffset.entrySet()) { b(XmlKeyword.diskOffset); a("untilVersion", e.getKey()); a("width", e.getValue()); el(); } if (ai.defaultWidth.value != 0) { bcl(XmlKeyword.defaultWidth); bcpel(XmlKeyword.lambda, ai.defaultWidth.value); el(XmlKeyword.defaultWidth); } for (Xml.ArcLayer al : ai.arcLayers) { String style = al.style == Poly.Type.FILLED ? "FILLED" : "CLOSED"; b(XmlKeyword.arcLayer); a("layer", al.layer); a("style", style); double extend = al.extend.value; if (extend == 0) { el(); } else { cl(); bcpel(XmlKeyword.lambda, extend); el(XmlKeyword.arcLayer); } } el(XmlKeyword.arcProto); } private void writeXml(Xml.PrimitiveNodeGroup ng, Map> additionalAttributes) { if (ng.isSingleton) { PrimitiveNode n = ng.nodes.get(0); b(XmlKeyword.primitiveNode); a("name", n.name); a("fun", n.function.name()); cl(); bcpel(XmlKeyword.oldName, n.oldName); } else { bcl(XmlKeyword.primitiveNodeGroup); for (PrimitiveNode n : ng.nodes) { b(XmlKeyword.primitiveNode); a("name", n.name); a("fun", n.function.name()); if (n.oldName != null || n.highVt || n.lowVt || n.nativeBit || n.od18 || n.od25 || n.od33) { cl(); bcpel(XmlKeyword.oldName, n.oldName); if (n.lowVt) { bel(XmlKeyword.lowVt); } if (n.highVt) { bel(XmlKeyword.highVt); } if (n.nativeBit) { bel(XmlKeyword.nativeBit); } if (n.od18) { bel(XmlKeyword.od18); } if (n.od25) { bel(XmlKeyword.od25); } if (n.od33) { bel(XmlKeyword.od33); } el(XmlKeyword.primitiveNode); } else { el(); } } } if (ng.shrinkArcs) { bel(XmlKeyword.shrinkArcs); } if (ng.square) { bel(XmlKeyword.square); } if (ng.canBeZeroSize) { bel(XmlKeyword.canBeZeroSize); } if (ng.wipes) { bel(XmlKeyword.wipes); } if (ng.lockable) { bel(XmlKeyword.lockable); } if (ng.edgeSelect) { bel(XmlKeyword.edgeSelect); } if (ng.skipSizeInPalette) { bel(XmlKeyword.skipSizeInPalette); } if (ng.notUsed) { bel(XmlKeyword.notUsed); } if (ng.isSingleton) { PrimitiveNode n = ng.nodes.get(0); if (n.lowVt) { bel(XmlKeyword.lowVt); } if (n.highVt) { bel(XmlKeyword.highVt); } if (n.nativeBit) { bel(XmlKeyword.nativeBit); } if (n.od18) { bel(XmlKeyword.od18); } if (n.od25) { bel(XmlKeyword.od25); } if (n.od33) { bel(XmlKeyword.od33); } } for (Map.Entry e : ng.diskOffset.entrySet()) { EPoint p = e.getValue(); b(XmlKeyword.diskOffset); a("untilVersion", e.getKey()); a("x", p.getLambdaX()); a("y", p.getLambdaY()); el(); } if (ng.defaultWidth.value != 0) { bcl(XmlKeyword.defaultWidth); bcpel(XmlKeyword.lambda, ng.defaultWidth.value); el(XmlKeyword.defaultWidth); } if (ng.defaultHeight.value != 0) { bcl(XmlKeyword.defaultHeight); bcpel(XmlKeyword.lambda, ng.defaultHeight.value); el(XmlKeyword.defaultHeight); } bcl(XmlKeyword.nodeBase); bcl(XmlKeyword.box); b(XmlKeyword.lambdaBox); a("klx", ng.baseLX.value); a("khx", ng.baseHX.value); a("kly", ng.baseLY.value); a("khy", ng.baseHY.value); el(); el(XmlKeyword.box); el(XmlKeyword.nodeBase); if (ng.protection != null) { b(XmlKeyword.protection); a("location", ng.protection); el(); } for (int j = 0; j < ng.nodeLayers.size(); j++) { Xml.NodeLayer nl = ng.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", Boolean.valueOf(nl.inElectricalLayers)); } if (additionalAttributes != null) { Map attrs = additionalAttributes.get(nl); if (attrs != null) { for (Map.Entry e : attrs.entrySet()) { a(e.getKey(), e.getValue()); } } } cl(); if (nl.inNodes != null) { assert !ng.isSingleton; bcl(XmlKeyword.inNodes); for (int i = 0; i < ng.nodes.size(); i++) { if (nl.inNodes.get(i)) { b(XmlKeyword.primitiveNode); a("name", ng.nodes.get(i).name); el(); } } el(XmlKeyword.inNodes); } switch (nl.representation) { case com.sun.electric.technology.Technology.NodeLayer.BOX: if (ng.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(); b(XmlKeyword.lambdaBox); a("klx", nl.lx.value); a("khx", nl.hx.value); a("kly", nl.ly.value); a("khy", nl.hy.value); el(); el(XmlKeyword.serpbox); } else { writeBox(XmlKeyword.box, nl.lx, nl.hx, nl.ly, nl.hy); cl(); b(XmlKeyword.lambdaBox); a("klx", nl.lx.value); a("khx", nl.hx.value); a("kly", nl.ly.value); a("khy", nl.hy.value); el(); 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("sizex", nl.sizex); a("sizey", nl.sizey); a("sep1d", nl.sep1d); a("sep2d", nl.sep2d); cl(); b(XmlKeyword.lambdaBox); a("klx", nl.lx.value); a("khx", nl.hx.value); a("kly", nl.ly.value); a("khy", nl.hy.value); el(); el(XmlKeyword.multicutbox); break; } for (TechPoint tp : nl.techPoints) { double xm = tp.getX().getMultiplier(); double xa = tp.getX().getAdder().getLambda(); double ym = tp.getY().getMultiplier(); double ya = tp.getY().getAdder().getLambda(); b(XmlKeyword.techPoint); a("xm", xm); a("xa", xa); a("ym", ym); a("ya", ya); el(); } el(XmlKeyword.nodeLayer); } for (int j = 0; j < ng.ports.size(); j++) { Xml.PrimitivePort pd = ng.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(); b(XmlKeyword.lambdaBox); a("klx", pd.lx.value); a("khx", pd.hx.value); a("kly", pd.ly.value); a("khy", pd.hy.value); el(); el(XmlKeyword.box); for (String portArc : pd.portArcs) { bcpel(XmlKeyword.portArc, portArc); } el(XmlKeyword.primitivePort); } switch (ng.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, ng.specialValues[i]); } el(XmlKeyword.serpTrans); break; } if (ng.nodeSizeRule != null) { NodeSizeRule r = ng.nodeSizeRule; b(XmlKeyword.minSizeRule); a("width", r.width); a("height", r.height); a("rule", r.rule); el(); } if (ng.spiceTemplate != null) { b(XmlKeyword.spiceTemplate); a("value", ng.spiceTemplate); el(); } el(ng.isSingleton ? XmlKeyword.primitiveNode : XmlKeyword.primitiveNodeGroup); } 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 writeSpiceHeaderXml(Xml.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(); } public void writeMenuPaletteXml(Xml.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 list) { b(XmlKeyword.menuBox); if (list == null || list.size() == 0) { el(); return; } cl(); for (Object o : list) { if (o instanceof Xml.ArcProto) { bcpel(XmlKeyword.menuArc, ((Xml.ArcProto) o).name); } else if (o instanceof Xml.PrimitiveNode) { bcpel(XmlKeyword.menuNode, ((Xml.PrimitiveNode) o).name); } else if (o instanceof Xml.MenuNodeInst) { Xml.MenuNodeInst ni = (Xml.MenuNodeInst) o; b(XmlKeyword.menuNodeInst); a("protoName", ni.protoName); a("function", ni.function.name()); if (ni.techBits != 0) { a("techBits", ni.techBits); } 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 writeFoundryXml(Xml.Foundry foundry) { b(XmlKeyword.Foundry); a("name", foundry.name); cl(); l(); for (Map.Entry 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(""); } private void comment(String s) { checkIndent(); 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 a(String name, double value) { a(name, new Double(value)); } private void a(String name, int value) { a(name, new Integer(value)); } private void bcpel(XmlKeyword key, Object v) { if (v == null) { return; } b(key); c(); p(v.toString()); el(key); } private void bcpel(XmlKeyword key, int v) { bcpel(key, new Integer(v)); } private void bcpel(XmlKeyword key, double v) { bcpel(key, new Double(v)); } 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 e() { assert indentEmitted; out.print("/>"); indent -= INDENT_WIDTH; } private void el(XmlKeyword key) { indent -= INDENT_WIDTH; checkIndent(); out.print(""); l(); } protected void checkIndent() { if (indentEmitted) { return; } for (int i = 0; i < indent; i++) { out.print(' '); } indentEmitted = true; } /** * Print new line. */ protected void l() { out.println(); indentEmitted = false; } } /** * 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; } } }