/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ELIB.java
* Input/output tool: ELIB Library output
* Written by Steven M. Rubin, Sun Microsystems.
*
* 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.tool.io.output;
import com.sun.electric.database.CellBackup;
import com.sun.electric.database.CellRevision;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.ImmutableCell;
import com.sun.electric.database.ImmutableElectricObject;
import com.sun.electric.database.ImmutableExport;
import com.sun.electric.database.ImmutableIconInst;
import com.sun.electric.database.ImmutableLibrary;
import com.sun.electric.database.ImmutableNodeInst;
import com.sun.electric.database.ImmutablePortInst;
import com.sun.electric.database.LibraryBackup;
import com.sun.electric.database.Snapshot;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.id.ArcProtoId;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.id.ExportId;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.LibId;
import com.sun.electric.database.id.NodeProtoId;
import com.sun.electric.database.id.PortProtoId;
import com.sun.electric.database.id.PrimitiveNodeId;
import com.sun.electric.database.id.TechId;
import com.sun.electric.database.prototype.PortProto;
import com.sun.electric.database.text.CellName;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.Version;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.variable.CodeExpression;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.Variable;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.PrimitiveNode;
import com.sun.electric.technology.PrimitivePort;
import com.sun.electric.technology.TechPool;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.Tool;
import com.sun.electric.tool.io.ELIBConstants;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.Orientation;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* This class writes files in binary (.elib) format.
*/
public class ELIB extends Output {
/** Snapshot being saved. */
Snapshot snapshot;
/** IdManager of Snapshot being saved. */
IdManager idManager;
/** TechPool of Snapshot being saved. */
TechPool techPool;
/** Library being saved. */
LibId theLibId;
/** Map of referenced objects for library files */
HashMap<Object, Integer> objInfo;
/** List of referenced Technologies */
final ArrayList<Technology> technologies = new ArrayList<Technology>();
/** Maps memory face index to disk face index */
private int[] faceMap = new int[TextDescriptor.ActiveFont.getMaxIndex() + 1];
/** Name space of variable names */
private TreeMap<String, Short> nameSpace;
/** Scale for irrelevant technologies. */
private double irrelevantScale;
/** map with "next in cell group" pointers */
private HashMap<CellId, CellId> cellInSameGroup = new HashMap<CellId, CellId>();
/** true to write a 6.XX compatible library (MAGIC11) */
private boolean compatibleWith6;
/** map to assign indices to cell names (for 6.XX) */
private TreeMap<String, Integer> cellIndexMap = new TreeMap<String, Integer>(TextUtils.STRING_NUMBER_ORDER);
/** Project preferences. */
private HashMap<Setting, Object> projectSettings = new HashMap<Setting, Object>();
/** size correctors for technologies */
private HashMap<TechId, Technology.SizeCorrector> sizeCorrectors = new HashMap<TechId, Technology.SizeCorrector>();
/** Topological sort of cells in library to be written */
private LinkedHashMap<CellId, Integer> cellOrdering = new LinkedHashMap<CellId, Integer>();
/** Map from nodeId to nodeIndex for current Cell. */
int[] nodeIndexByNodeId;
ArrayList<CellRevision> localCells = new ArrayList<CellRevision>();
ArrayList<CellRevision> externalCells = new ArrayList<CellRevision>();
int nodeIndex = 0;
int portProtoIndex = 0;
int nodeProtoIndex = 0;
int arcIndex = 0;
int primNodeProtoIndex = 0;
int primPortProtoIndex = 0;
int arcProtoIndex = 0;
int toolCount = 0;
int[] primNodeCounts;
int[] primArcCounts;
int[] groupRenumber;
ELIB() {
}
public void write6Compatible() {
compatibleWith6 = true;
}
// ----------------------- public methods -------------------------------
/**
* Method to write a Library in binary (.elib) format.
* @param snapshot Snapshot to be written
* @param theLibId the Library to be written.
*/
protected boolean writeLib(Snapshot snapshot, LibId theLibId) {
this.snapshot = snapshot;
idManager = snapshot.idManager;
techPool = snapshot.techPool;
this.theLibId = theLibId;
// Gather objects referenced from Cells
objInfo = new HashMap<Object, Integer>();
nameSpace = new TreeMap<String, Short>(TextUtils.STRING_NUMBER_ORDER);
for (CellBackup cellBackup : snapshot.cellBackups) {
if (cellBackup == null) {
continue;
}
CellRevision cellRevision = cellBackup.cellRevision;
CellId cellId = cellRevision.d.cellId;
if (cellId.libId != theLibId) {
continue;
}
gatherCell(cellRevision.d.cellId);
for (ImmutableNodeInst n : cellRevision.nodes) {
NodeProtoId np = n.protoId;
if (np instanceof CellId) {
gatherCell((CellId) np);
} else {
gatherObj(np);
gatherTech(((PrimitiveNodeId) np).techId);
}
if (n.hasPortInstVariables()) {
for (Iterator<PortProtoId> it = n.getPortsWithVariables(); it.hasNext();) {
PortProtoId portId = it.next();
gatherVariables(portId.getName(snapshot), n.getPortInst(portId));
}
}
gatherVariables(null, n);
gatherFont(n.nameDescriptor);
gatherFont(n.protoDescriptor);
}
for (ImmutableArcInst a : cellRevision.arcs) {
ArcProtoId apId = a.protoId;
gatherObj(apId);
gatherTech(apId.techId);
//gatherObj(ai.getHead().getPortInst().getPortProto());
//gatherObj(ai.getTail().getPortInst().getPortProto());
gatherVariables(null, a);
gatherFont(a.nameDescriptor);
}
for (ImmutableExport e : cellRevision.exports) {
//gatherObj(e.getOriginalPort().getPortProto());
gatherVariables(null, e);
gatherFont(e.nameDescriptor);
}
gatherVariables(null, cellRevision.d);
}
gatherVariables(null, snapshot.getLib(theLibId).d);
// Gather objects refetenced from preferences
for (Iterator<Tool> it = Tool.getTools(); it.hasNext();) {
gatherSettings(it.next());
}
for (Iterator<Technology> it = Technology.getTechnologies(); it.hasNext();) {
Technology tech = it.next();
TechId techId = tech.getId();
if (!objInfo.containsKey(techId)) {
continue;
}
technologies.add(tech);
gatherSettings(tech);
}
putNameSpace(Library.FONT_ASSOCIATIONS.getName());
putNameSpace(NodeInst.NODE_NAME.getName());
putNameSpace(ArcInst.ARC_NAME.getName());
short varIndex = 0;
for (Map.Entry<String, Short> e : nameSpace.entrySet()) {
e.setValue(new Short(varIndex++));
}
// make sure all technologies with irrelevant scale information have the same scale value
for (Technology tech : technologies) {
if (tech.isScaleRelevant()) {
continue;
}
if (tech == Generic.tech()) {
continue;
}
irrelevantScale = Math.max(irrelevantScale, tech.getScale());
}
// Sort CellIds
TreeMap<String, LibId> sortedLibIds = new TreeMap<String, LibId>(TextUtils.STRING_NUMBER_ORDER);
HashMap<LibId, TreeMap<CellName, CellId>> sortedCellIds = new HashMap<LibId, TreeMap<CellName, CellId>>();
for (CellBackup cellBackup : snapshot.cellBackups) {
if (cellBackup == null) {
continue;
}
CellId cellId = cellBackup.cellRevision.d.cellId;
if (!objInfo.containsKey(cellId)) {
continue;
}
LibId libId = cellId.libId;
sortedLibIds.put(libId.libName, libId);
TreeMap<CellName, CellId> sortedCellIdsInLibrary = sortedCellIds.get(libId);
if (sortedCellIdsInLibrary == null) {
sortedCellIdsInLibrary = new TreeMap<CellName, CellId>();
sortedCellIds.put(libId, sortedCellIdsInLibrary);
}
sortedCellIdsInLibrary.put(cellId.cellName, cellId);
}
for (CellId cellId : sortedCellIds.get(theLibId).values()) {
localCells.add(snapshot.getCellRevision(cellId));
}
// count and number the cells, nodes, arcs, and ports in this library
int maxGroup = -1;
ArrayList<TreeMap<CellName, CellId>> cellGroups_ = new ArrayList<TreeMap<CellName, CellId>>();
for (CellRevision cellRevision : localCells) {
maxGroup = Math.max(maxGroup, snapshot.getCellGroupIndex(cellRevision.d.cellId));
}
groupRenumber = new int[maxGroup + 1];
for (CellRevision cellRevision : localCells) {
CellId cellId = cellRevision.d.cellId;
cellOrdering.put(cellId, new Integer(nodeProtoIndex));
putObjIndex(cellId, nodeProtoIndex++);
for (ImmutableExport e : cellRevision.exports) {
putObjIndex(e.exportId, portProtoIndex++);
}
nodeIndex += cellRevision.nodes.size();
arcIndex += cellRevision.arcs.size();
int snapshotGroup = snapshot.getCellGroupIndex(cellId);
int elibGroup = groupRenumber[snapshotGroup];
if (elibGroup == 0) {
cellGroups_.add(new TreeMap<CellName, CellId>());
elibGroup = cellGroups_.size();
groupRenumber[snapshotGroup] = elibGroup;
}
cellGroups_.get(elibGroup - 1).put(cellId.cellName, cellId);
// gather proto name if creating version-6-compatible output
if (compatibleWith6) {
String protoName = cellId.cellName.getName();
if (!cellIndexMap.containsKey(protoName)) {
cellIndexMap.put(protoName, null);
}
}
}
for (int i = 0; i < cellGroups_.size(); i++) {
TreeMap<CellName, CellId> cellGroup_ = cellGroups_.get(i);
Iterator<CellId> git = cellGroup_.values().iterator();
CellId firstCellInGroup = git.next();
CellId lastCellInGroup = firstCellInGroup;
while (git.hasNext()) {
CellId cellInGroup = git.next();
// assert cellInSameGroup.get(lastCellInGroup) == cellInGroup;
cellInSameGroup.put(lastCellInGroup, cellInGroup);
lastCellInGroup = cellInGroup;
}
// assert cellInSameGroup.get(lastCellInGroup) == firstCellInGroup;
cellInSameGroup.put(lastCellInGroup, firstCellInGroup);
}
// count and number the cells in other libraries
for (LibId libId : sortedLibIds.values()) {
if (libId == theLibId) {
continue;
}
for (CellId cellId : sortedCellIds.get(libId).values()) {
assert objInfo.containsKey(cellId);
CellRevision cellRevision = snapshot.getCellRevision(cellId);
externalCells.add(cellRevision);
putObjIndex(cellId, nodeProtoIndex++);
for (ImmutableExport e : cellRevision.exports) {
putObjIndex(e.exportId, portProtoIndex++);
}
// gather proto name if creating version-6-compatible output
if (compatibleWith6) {
String protoName = cellId.cellName.getName();
if (!cellIndexMap.containsKey(protoName)) {
cellIndexMap.put(protoName, null);
}
}
}
}
// count the number of primitives
primNodeCounts = new int[technologies.size()];
primArcCounts = new int[technologies.size()];
for (int techCount = 0; techCount < technologies.size(); techCount++) {
Technology tech = technologies.get(techCount);
TechId techId = tech.getId();
putObjIndex(techId, techCount);
int primNodeStart = primNodeProtoIndex;
for (Iterator<PrimitiveNode> nit = tech.getNodes(); nit.hasNext();) {
PrimitiveNode np = nit.next();
if (!objInfo.containsKey(np.getId())) {
continue;
}
putObjIndex(np.getId(), -2 - primNodeProtoIndex++);
for (Iterator<PortProto> pit = np.getPorts(); pit.hasNext();) {
PrimitivePort pp = (PrimitivePort) pit.next();
putObjIndex(pp.getId(), -2 - primPortProtoIndex++);
}
}
primNodeCounts[techCount] = primNodeProtoIndex - primNodeStart;
int primArcStart = arcProtoIndex;
for (Iterator<ArcProto> ait = tech.getArcs(); ait.hasNext();) {
ArcProtoId apId = ait.next().getId();
if (!objInfo.containsKey(apId)) {
continue;
}
putObjIndex(apId, -2 - arcProtoIndex++);
}
primArcCounts[techCount] = arcProtoIndex - primArcStart;
}
// count the number of tools
for (Iterator<Tool> it = Tool.getTools(); it.hasNext();) {
Tool tool = it.next();
if (!objInfo.containsKey(tool)) {
continue;
}
toolCount++;
}
try {
return writeTheLibrary();
} catch (IOException e) {
System.out.println("End of file reached while writing " + filePath);
return true;
}
}
/**
* Method to write the .elib file.
* Returns true on error.
*/
boolean writeTheLibrary() throws IOException {
// write the header
int magic = ELIBConstants.MAGIC13;
if (compatibleWith6) {
magic = ELIBConstants.MAGIC11;
}
writeBigInteger(magic);
writeByte((byte) 2); // size of Short
writeByte((byte) 4); // size of Int
writeByte((byte) 1); // size of Char
// write number of objects
writeBigInteger(toolCount);
writeBigInteger(technologies.size());
writeBigInteger(primNodeProtoIndex);
writeBigInteger(primPortProtoIndex);
writeBigInteger(arcProtoIndex);
writeBigInteger(nodeProtoIndex);
writeBigInteger(nodeIndex);
writeBigInteger(portProtoIndex);
writeBigInteger(arcIndex);
writeBigInteger(0);
// write count of cells if creating version-6-compatible output
int cellCount = 0;
if (compatibleWith6) {
for (Map.Entry<String, Integer> e : cellIndexMap.entrySet()) {
e.setValue(new Integer(cellCount++));
}
writeBigInteger(cellCount);
}
// write the current cell
writeObj(null);
// write the version number
writeString(Version.getVersion().toOldStyleString());
// number the views and write nonstandard ones
putObjIndex(View.UNKNOWN, -1);
putObjIndex(View.LAYOUT, -2);
putObjIndex(View.SCHEMATIC, -3);
putObjIndex(View.ICON, -4);
putObjIndex(View.DOCWAVE, -5); // unknown in C
putObjIndex(View.LAYOUTSKEL, -6); // unknown in C
putObjIndex(View.VHDL, -7);
putObjIndex(View.NETLIST, -8);
putObjIndex(View.DOC, -9);
putObjIndex(View.NETLISTNETLISP, -10); // unknown in C
putObjIndex(View.NETLISTALS, -11); // unknown in C
putObjIndex(View.NETLISTQUISC, -12); // unknown in C
putObjIndex(View.NETLISTRSIM, -13); // unknown in C
putObjIndex(View.NETLISTSILOS, -14); // unknown in C
putObjIndex(View.VERILOG, -15);
List<View> viewsToSave = new ArrayList<View>();
for (Iterator<View> it = View.getViews(); it.hasNext();) {
View view = it.next();
if (objInfo.get(view) != null) {
continue;
}
if (!objInfo.containsKey(view)) {
continue;
}
viewsToSave.add(view);
putObjIndex(view, viewsToSave.size());
}
writeBigInteger(viewsToSave.size());
for (View view : viewsToSave) {
writeString(view.getFullName());
writeString(view.getAbbreviation());
}
// write total number of arcinsts, nodeinsts, and ports in each cell
for (CellId cellId : cellOrdering.keySet()) {
CellRevision cellRevision = snapshot.getCellRevision(cellId);
writeBigInteger(cellRevision.arcs.size());
writeBigInteger(cellRevision.nodes.size());
writeBigInteger(cellRevision.exports.size());
}
// write dummy numbers of arcinsts and nodeinst; count ports for external cells
for (CellRevision cellRevision : externalCells) {
CellId cellId = cellRevision.d.cellId;
if (!objInfo.containsKey(cellId)) {
continue;
}
writeBigInteger(-1);
writeBigInteger(-1);
writeBigInteger(cellRevision.exports.size());
}
// write the names of technologies and primitive prototypes
for (int techCount = 0; techCount < technologies.size(); techCount++) {
Technology tech = technologies.get(techCount);
// write the technology name
writeString(tech.getTechName());
// write the primitive node prototypes
writeBigInteger(primNodeCounts[techCount]);
for (Iterator<PrimitiveNode> nit = tech.getNodes(); nit.hasNext();) {
PrimitiveNode np = nit.next();
if (!objInfo.containsKey(np.getId())) {
continue;
}
// write the primitive node prototype name
writeString(np.getName());
writeBigInteger(np.getNumPorts());
for (Iterator<PortProto> pit = np.getPorts(); pit.hasNext();) {
PrimitivePort pp = (PrimitivePort) pit.next();
writeString(pp.getName());
}
}
// write the primitive arc prototype names
writeBigInteger(primArcCounts[techCount]);
for (Iterator<ArcProto> ait = tech.getArcs(); ait.hasNext();) {
ArcProtoId apId = ait.next().getId();
if (!objInfo.containsKey(apId)) {
continue;
}
writeString(apId.name);
}
}
// write the names of the tools
for (Iterator<Tool> it = Tool.getTools(); it.hasNext();) {
Tool tool = it.next();
if (!objInfo.containsKey(tool)) {
continue;
}
writeString(tool.getName());
}
// write the userbits for the library
writeBigInteger(0);
//writeBigInteger(lib.lowLevelGetUserBits());
// write the tool scale values
for (Technology tech : technologies) {
writeBigInteger(gridCoordToElib(tech, DBMath.GRID));
// writeBigInteger((int)Math.round(tech.getScale()*2));
}
// write the global namespace
writeNameSpace();
// write the library variables and font association that preserves the font names
writeVariables(snapshot.getLib(theLibId).d);
// write the tool variables
for (Iterator<Tool> it = Tool.getTools(); it.hasNext();) {
Tool tool = it.next();
if (!objInfo.containsKey(tool)) {
continue;
}
writeMeaningPrefs(tool);
}
// write the variables on technologies
for (Technology tech : technologies) {
writeMeaningPrefs(tech);
}
// write the dummy primitive variables
int numDummyVariables = arcProtoIndex + primNodeProtoIndex + primPortProtoIndex;
for (int i = 0; i < numDummyVariables; i++) {
writeNoVariables();
}
// write the dummy view variables
writeBigInteger(0);
// write cells if creating version-6-compatible output
if (compatibleWith6) {
for (String cellName : cellIndexMap.keySet()) {
writeString(cellName);
writeNoVariables();
}
}
// write all of the cells in this library
nodeIndex = 0;
for (CellId cellId : cellOrdering.keySet()) {
CellRevision cellRevision = snapshot.getCellRevision(cellId);
startCell(cellRevision, nodeIndex);
writeNodeProto(cellRevision);
nodeIndex += cellRevision.nodes.size();
}
// write all of the cells in external libraries
writeExternalCells();
// write all of the arcs and nodes in this library
nodeIndex = 0;
arcIndex = 0;
for (CellId cellId : cellOrdering.keySet()) {
CellRevision cellRevision = snapshot.getCellRevision(cellId);
startCell(cellRevision, nodeIndex);
writeArcs(cellRevision);
writeNodes(snapshot.getCell(cellId), arcIndex);
nodeIndex += cellRevision.nodes.size();
arcIndex += cellRevision.arcs.size();
}
// library written successfully
return false;
}
/**
* Gather variables of ElectricObject into objInfo map.
* @param eObj ElectricObject with variables.
*/
private void gatherVariables(String portName, ImmutableElectricObject d) {
if (d instanceof ImmutableCell) {
for (Iterator<Variable> it = ((ImmutableCell) d).getParameters(); it.hasNext();) {
Variable param = it.next();
gatherVariable(portName, param);
}
} else if (d instanceof ImmutableIconInst) {
for (Iterator<Variable> it = ((ImmutableIconInst) d).getDefinedParameters(); it.hasNext();) {
Variable param = it.next();
gatherVariable(portName, param);
}
}
for (Iterator<Variable> it = d.getVariables(); it.hasNext();) {
Variable var = it.next();
gatherVariable(portName, var);
}
}
/**
* Gather variable into objInfo map.
* @param var variable.
*/
private void gatherVariable(String portName, Variable var) {
Object value = var.getObject();
if (nameSpace != null) {
putNameSpace(diskName(portName, var));
}
gatherFont(var.getTextDescriptor());
int length = value instanceof Object[] ? ((Object[]) value).length : 1;
for (int i = 0; i < length; i++) {
Object v = value instanceof Object[] ? ((Object[]) value)[i] : value;
if (v == null) {
continue;
}
if (v instanceof TechId || v instanceof Tool) {
gatherObj(v);
} else if (v instanceof PrimitiveNodeId) {
gatherObj(v);
gatherTech(((PrimitiveNodeId) v).techId);
} else if (v instanceof PrimitivePort) {
PrimitiveNode pn = ((PrimitivePort) v).getParent();
gatherObj(pn.getId());
gatherTech(pn.getTechnology().getId());
} else if (v instanceof ArcProto) {
gatherObj(v);
gatherTech(((ArcProto) v).getId().techId);
} else if (v instanceof CellId) {
CellId cellId = (CellId) v;
if (snapshot.getCell(cellId) != null) {
gatherCell(cellId);
}
} else if (v instanceof ExportId) {
ExportId exportId = (ExportId) v;
CellRevision cellRevision = snapshot.getCellRevision(exportId.getParentId());
if (cellRevision != null && cellRevision.getExport(exportId) != null) {
gatherObj(exportId);
gatherCell(exportId.getParentId());
}
}
}
}
/**
* Gather project preferences attached to object into objInfo map.
* @param obj Object with attached project preferences.
*/
private void gatherSettings(Object obj) {
Setting.Group group = null;
if (obj instanceof Tool) {
group = ((Tool) obj).getProjectSettings();
} else if (obj instanceof Technology) {
group = ((Technology) obj).getProjectSettings();
}
for (Setting setting : group.getDiskSettings(snapshot.getSettings()).keySet()) {
gatherObj(obj);
String name = setting.getPrefName();
if (nameSpace != null) {
putNameSpace(name);
}
}
}
/**
* Gather TechId of Technology into objInfo map.
* @param tech Technology to examine.
*/
private void gatherTech(TechId techId) {
gatherObj(techId);
}
/**
* Gather Cell, its Library and its font into objInfo map.
* @param cell Cell to examine.
*/
private void gatherCell(CellId cellId) {
gatherObj(cellId);
gatherObj(cellId.libId);
gatherObj(cellId.cellName.getView());
}
/**
* Gather object into objInfo map.
* @param obj Object to put.
*/
private void gatherObj(Object obj) {
objInfo.put(obj, null);
}
/**
* Put index of object into objInfo map.
* @param obj Object to put.
* @param index index of object.
*/
private void putObjIndex(Object obj, int index) {
objInfo.put(obj, new Integer(index));
}
/**
* Put string into variable name space.
* @param name name to put.
*/
private void putNameSpace(String name) {
nameSpace.put(name, null);
}
/**
* Gather ActiveFont object of the TextDescriptor into objInfo map.
* @param td TextDescriptor to examine.
*/
private void gatherFont(TextDescriptor td) {
int face = td.getFace();
faceMap[face] = -1;
}
/**
* Method to gather all font settings in a Library.
* The method examines all TextDescriptors that might be saved with the Library
* and returns an array of Strings that describes the font associations.
* Each String is of the format NUMBER/FONTNAME where NUMBER is the font number
* in the TextDescriptor and FONTNAME is the font name.
* @return font association array or null.
*/
String[] createFontAssociation() {
TreeMap<String, TextDescriptor.ActiveFont> sortedFonts = new TreeMap<String, TextDescriptor.ActiveFont>();
for (int face = 1; face < faceMap.length; face++) {
if (faceMap[face] == 0) {
continue;
}
TextDescriptor.ActiveFont af = TextDescriptor.ActiveFont.findActiveFont(face);
sortedFonts.put(af.getName(), af);
}
if (sortedFonts.size() == 0) {
return null;
}
String[] fontAssociation = new String[sortedFonts.size()];
int elibFace = 0;
for (TextDescriptor.ActiveFont af : sortedFonts.values()) {
elibFace++;
faceMap[af.getIndex()] = elibFace;
fontAssociation[elibFace - 1] = elibFace + "/" + af.getName();
}
return fontAssociation;
}
void startCell(CellRevision cellRevision, int baseNodeIndex) {
int maxNodeId = -1;
for (ImmutableNodeInst n : cellRevision.nodes) {
maxNodeId = Math.max(maxNodeId, n.nodeId);
}
nodeIndexByNodeId = new int[maxNodeId + 1];
for (int nodeIndex = 0; nodeIndex < cellRevision.nodes.size(); nodeIndex++) {
ImmutableNodeInst n = cellRevision.nodes.get(nodeIndex);
nodeIndexByNodeId[n.nodeId] = nodeIndex + baseNodeIndex;
}
}
// --------------------------------- OBJECT CONVERSION ---------------------------------
void writeExternalCells() throws IOException {
for (int i = 0; i < externalCells.size(); i++) {
CellRevision cellRevision = externalCells.get(i);
CellId cellId = cellRevision.d.cellId;
writeTxt("***cell: " + i); // TXT only
writeCellInfo(cellRevision);
LibraryBackup libBackup = snapshot.getLib(cellId.libId);
URL fileUrl = libBackup.d.libFile;
String filePath = fileUrl != null ? fileUrl.getPath() : libBackup.d.libId.libName;
writeTxt("externallibrary: \"" + filePath + "\""); // TXT only
if (this instanceof ReadableDump) {
continue;
}
writeString(filePath);
// write the number of portprotos on this nodeproto
writeBigInteger(cellRevision.exports.size());
for (ImmutableExport e : cellRevision.exports) {
// write the portproto name
writeString(e.name.toString());
}
}
}
void writeCellInfo(CellRevision cellRevision) throws IOException {
CellId cellId = cellRevision.d.cellId;
if (this instanceof ReadableDump) {
writeTxt("name: " + cellId.cellName.getName() + cellId.cellName.getView().getAbbreviationExtension());
} else {
if (compatibleWith6) {
// write cell index if creating version-6-compatible output
Integer cellIndex = cellIndexMap.get(cellId.cellName.getName());
writeBigInteger(cellIndex.intValue());
} else {
// write cell information
writeString(cellId.cellName.getName());
// write the "next in cell group" pointer
writeObj(cellInSameGroup.get(cellId));
// write the "next in continuation" pointer
writeObj(null);
}
// write the view information
writeObj(cellId.cellName.getView());
}
writeInt("version: ", cellId.cellName.getVersion());
writeInt("creationdate: ", (int) (cellRevision.d.creationDate / 1000));
writeInt("revisiondate: ", (int) (cellRevision.d.revisionDate / 1000));
// write the nodeproto bounding box
ERectangle bounds = snapshot.getCellBounds(cellId);
writeGridCoord(cellRevision, "lowx: ", bounds.getGridMinX());
writeGridCoord(cellRevision, "highx: ", bounds.getGridMaxX());
writeGridCoord(cellRevision, "lowy: ", bounds.getGridMinY());
writeGridCoord(cellRevision, "highy: ", bounds.getGridMaxY());
// Technology tech = cellBackup.d.tech;
// int lowX = (int)Math.round((bounds.getLambdaMinX() * tech.getScale()*2));
// int highX = (int)Math.round((bounds.getLambdaMaxX() * tech.getScale()*2));
// int lowY = (int)Math.round((bounds.getLambdaMinY() * tech.getScale()*2));
// int highY = (int)Math.round((bounds.getLambdaMaxY() * tech.getScale()*2));
// writeInt("lowx: ", lowX);
// writeInt("highx: ", highX);
// writeInt("lowy: ", lowY);
// writeInt("highy: ", highY);
}
private void writeNodeProto(CellRevision cellRevision) throws IOException {
writeCellInfo(cellRevision);
writeExports(cellRevision);
// write tool information
writeBigInteger(0); // was "adirty"
writeBigInteger(cellRevision.d.flags & ELIBConstants.CELL_BITS);
// write variable information
writeVariables(cellRevision.d);
}
void writeNodes(CellBackup cellBackup, int arcBase) throws IOException {
// Technology tech = cellBackup.d.tech;
CellBackup.Memoization m = cellBackup.getMemoization();
CellRevision cellRevision = cellBackup.cellRevision;
for (int nodeIndex = 0; nodeIndex < cellRevision.nodes.size(); nodeIndex++) {
ImmutableNodeInst n = cellRevision.nodes.get(nodeIndex);
writeTxt("**node: " + nodeIndex);
// write descriptive information
// int lowX, highX, lowY, highY;
double trueCenterX, trueCenterY, xSize, ySize;
NodeProtoId protoId = n.protoId;
writeObj(protoId);
if (protoId instanceof CellId) {
writeTxt("type: [" + objInfo.get(protoId).intValue() + "]");
ERectangle bounds = snapshot.getCellBounds((CellId) protoId);
Rectangle2D dstBounds = new Rectangle2D.Double();
n.orient.rectangleBounds(bounds.getGridMinX(), bounds.getGridMinY(), bounds.getGridMaxX(), bounds.getGridMaxY(), n.anchor.getGridX(), n.anchor.getGridY(), dstBounds);
trueCenterX = dstBounds.getCenterX();
trueCenterY = dstBounds.getCenterY();
xSize = bounds.getGridWidth();
ySize = bounds.getGridHeight();
// lowX = (int)Math.round((trueCenterX - xSize/2) * tech.getScale()*2);
// highX = (int)Math.round((trueCenterX + xSize/2) * tech.getScale()*2);
// lowY = (int)Math.round((trueCenterY - ySize/2) * tech.getScale()*2);
// highY = (int)Math.round((trueCenterY + ySize/2) * tech.getScale()*2);
} else {
PrimitiveNodeId pn = (PrimitiveNodeId) protoId;
trueCenterX = n.anchor.getGridX();
trueCenterY = n.anchor.getGridY();
EPoint size = getSizeCorrector(pn.techId).getSizeToDisk(n);
xSize = size.getGridX();
ySize = size.getGridY();
writeTxt("type: " + pn.fullName);
// lowX = (int)Math.round((n.anchor.getLambdaX() - n.size.getLambdaX()/2) * tech.getScale()*2);
// highX = (int)Math.round((n.anchor.getLambdaX() + n.size.getLambdaX()/2) * tech.getScale()*2);
// lowY = (int)Math.round((n.anchor.getLambdaY() - n.size.getLambdaY()/2) * tech.getScale()*2);
// highY = (int)Math.round((n.anchor.getLambdaY() + n.size.getLambdaY()/2) * tech.getScale()*2);
}
writeGridCoord(cellRevision, "lowx: ", trueCenterX - xSize * 0.5);
writeGridCoord(cellRevision, "lowy: ", trueCenterY - ySize * 0.5);
writeGridCoord(cellRevision, "highx: ", trueCenterX + xSize * 0.5);
writeGridCoord(cellRevision, "highy: ", trueCenterY + ySize * 0.5);
// writeInt("lowx: ", lowX);
// writeInt("lowy: ", lowY);
// writeInt("highx: ", highX);
// writeInt("highy: ", highY);
// write anchor point too
if (protoId instanceof CellId && !compatibleWith6) {
writeGridCoord(cellRevision, null, n.anchor.getGridX());
writeGridCoord(cellRevision, null, n.anchor.getGridY());
// int anchorX = (int)Math.round(n.anchor.getLambdaX() * tech.getScale() * 2);
// int anchorY = (int)Math.round(n.anchor.getLambdaY() * tech.getScale() * 2);
// writeBigInteger(anchorX);
// writeBigInteger(anchorY);
}
Orientation or = n.orient;
int transpose = 0;
int rotation;
if (compatibleWith6) {
rotation = or.getCAngle();
transpose = or.isCTranspose() ? 1 : 0;
} else {
rotation = or.getAngle();
if (or.isXMirrored()) {
transpose |= 2;
}
if (or.isYMirrored()) {
transpose |= 4;
}
}
writeOrientation(rotation, transpose);
TextDescriptor td = protoId instanceof CellId ? n.protoDescriptor : null;
writeTextDescriptor(-1, td);
if (this instanceof ReadableDump) {
// write the tool information
writeInt("userbits: ", n.getElibBits());
// write variable information and arc name
writeVariables(n);
writeConnectionsAndReExports(m, arcBase, n);
} else {
writeConnectionsAndReExports(m, arcBase, n);
// write the tool information
writeBigInteger(n.getElibBits());
// write variable information and arc name
writeVariables(n);
}
}
}
private void writeConnectionsAndReExports(CellBackup.Memoization m, int arcBase, ImmutableNodeInst n) throws IOException {
int myNodeId = n.nodeId;
TreeSet<ElibConnection> sortedConnections = new TreeSet<ElibConnection>();
BitSet headEnds = new BitSet();
List<ImmutableArcInst> arcs = m.getConnections(headEnds, n, null);
for (int i = 0; i < arcs.size(); i++) {
ImmutableArcInst a = arcs.get(i);
boolean isHead = headEnds.get(i);
PortProtoId portId = isHead ? a.headPortId : a.tailPortId;
sortedConnections.add(new ElibConnection(portId, a.arcId, isHead, m.getArcIndex(a)));
}
assert sortedConnections.size() == arcs.size();
writeBigInteger(sortedConnections.size());
for (ElibConnection c : sortedConnections) {
writeConnection(c.portId, arcBase + c.arcIndex, c.isHead ? 1 : 0);
}
// write the exports
int numExports = m.getNumExports(n.nodeId);
writeBigInteger(numExports); // only ELIB
if (numExports > 0) {
// must write exports in proper order
TreeMap<String, ImmutableExport> sortedExports = new TreeMap<String, ImmutableExport>();
for (Iterator<ImmutableExport> it = m.getExports(n.nodeId); it.hasNext();) {
ImmutableExport e = it.next();
sortedExports.put(e.exportId.externalId, e);
}
for (ImmutableExport e : sortedExports.values()) {
writeReExport(e);
}
}
}
private static class ElibConnection implements Comparable<ElibConnection> {
private final PortProtoId portId;
private final int arcId;
private final boolean isHead;
private final int arcIndex;
private ElibConnection(PortProtoId portId, int arcId, boolean isHead, int arcIndex) {
this.portId = portId;
this.arcId = arcId;
this.isHead = isHead;
this.arcIndex = arcIndex;
}
public int compareTo(ElibConnection that) {
int cmp = TextUtils.STRING_NUMBER_ORDER.compare(this.portId.externalId, that.portId.externalId);
if (cmp != 0) {
return cmp;
}
cmp = this.arcId - that.arcId;
if (cmp != 0) {
return cmp;
}
if (this.isHead && !that.isHead) {
return 1;
}
if (!this.isHead && that.isHead) {
return -1;
}
return 0;
}
}
void writeArcs(CellRevision cellRevision) throws IOException {
// double gridScale = cellRevision.d.tech.getScale()*2/DBMath.GRID;
for (int arcIndex = 0; arcIndex < cellRevision.arcs.size(); arcIndex++) {
ImmutableArcInst a = cellRevision.arcs.get(arcIndex);
writeTxt("**arc: " + arcIndex); // TXT only
// write the arcproto pointer
writeObj(a.protoId); // ELIB only
writeTxt("type: " + a.protoId.fullName); // TXT only
// write basic arcinst information
int userBits = a.getElibBits();
long arcWidth = getSizeCorrector(a.protoId.techId).getWidthToDisk(a);
writeGridCoord(cellRevision, "width: ", arcWidth);
writeTxt("length: " + (int) Math.round(a.getGridLength() * getScale(cellRevision.d.techId) * 2 / DBMath.GRID));
// writeInt("width: ", (int)Math.round(a.getGridFullWidth() * gridScale));
// writeTxt("length: " + (int)Math.round(a.getGridLength() * gridScale));
writeTxt("userbits: " + userBits); // only TXT
// write the arcinst tail information
writeTxt("*end: 0");
writeGridCoord(cellRevision, "xpos: ", a.tailLocation.getGridX());
writeGridCoord(cellRevision, "ypos: ", a.tailLocation.getGridY());
// writeInt("xpos: ", (int)Math.round(a.tailLocation.getGridX() * gridScale));
// writeInt("ypos: ", (int)Math.round(a.tailLocation.getGridY() * gridScale));
writeInt("node: ", nodeIndexByNodeId[a.tailNodeId]);
writeTxt("nodeport: " + a.tailPortId.getName(snapshot));
// write the arcinst head information
writeTxt("*end: 1");
writeGridCoord(cellRevision, "xpos: ", a.headLocation.getGridX());
writeGridCoord(cellRevision, "ypos: ", a.headLocation.getGridY());
// writeInt("xpos: ", (int)Math.round(a.headLocation.getGridX() * gridScale));
// writeInt("ypos: ", (int)Math.round(a.headLocation.getGridY() * gridScale));
writeInt("node: ", nodeIndexByNodeId[a.headNodeId]);
writeTxt("nodeport: " + a.headPortId.getName(snapshot));
// write the arcinst's tool information
writeBigInteger(userBits); // ELIB only
// write variable information and arc name
writeVariables(a);
}
}
void writeExports(CellRevision cellRevision) throws IOException {
writeBigInteger(cellRevision.exports.size());
for (int exportIndex = 0; exportIndex < cellRevision.exports.size(); exportIndex++) {
ImmutableExport e = cellRevision.exports.get(exportIndex);
writeTxt("**porttype: " + exportIndex); // TXT only
// write the connecting subnodeinst for this portproto
writeInt("subnode: ", nodeIndexByNodeId[e.originalNodeId]);
// write the portproto index in the subnodeinst
writeObj(e.originalPortId); // ELIB only
writeTxt("subport: " + e.originalPortId.getName(snapshot)); // TXT only
// write the portproto name
if (!(this instanceof ReadableDump)) {
writeString(e.name.toString()); // ELIB only
}
writeTxt("name: " + e.name.toString()); // TXT only
// write the text descriptor
writeTextDescriptor(-1, e.nameDescriptor);
// write the portproto tool information
writeInt("userbits: ", e.getElibBits());
// write variable information
writeVariables(e);
}
}
void writeOrientation(int angle, int transpose) throws IOException {
writeBigInteger(transpose);
writeBigInteger(angle);
}
void writeConnection(PortProtoId portId, int arcIndex, int connIndex) throws IOException {
writeBigInteger((arcIndex << 1) | connIndex);
// write the portinst prototype
writeObj(portId);
// write the variable information
writeNoVariables();
}
void writeReExport(ImmutableExport e) throws IOException {
writeObj(e.exportId);
// write the portinst prototype
writeObj(e.originalPortId);
// write the variable information
writeNoVariables();
}
// --------------------------------- VARIABLES ---------------------------------
/**
* Method to write the global namespace. returns true upon error
*/
private void writeNameSpace() throws IOException {
if (nameSpace.size() > Short.MAX_VALUE) {
Job.getUserInterface().showErrorMessage(
"ERROR! Too many unique variable names\n"
+ "The ELIB format cannot handle this many unique variables names\n"
+ "Either delete the excess variables, or save to a readable dump",
"Error saving ELIB file");
throw new IOException("Variable.Key index too large");
}
writeBigInteger(nameSpace.size());
for (String str : nameSpace.keySet()) {
writeString(str);
}
}
/**
* Method to write an empty set of variables.
*/
private void writeNoVariables() throws IOException {
writeBigInteger(0);
}
/**
* Method to write a set of object variables. returns negative upon error and
* otherwise returns the number of variables write
*/
void writeVariables(ImmutableElectricObject d) throws IOException {
// write the number of Variables
int count = d.getNumVariables();
if (d instanceof ImmutableCell) {
count += ((ImmutableCell) d).getNumParameters();
} else if (d instanceof ImmutableIconInst) {
count += ((ImmutableIconInst) d).getNumDefinedParameters();
}
Variable.Key additionalVarKey = null;
int additionalVarType = ELIBConstants.VSTRING;
TextDescriptor additionalTextDescriptor = null;
Object additionalVarValue = null;
if (d instanceof ImmutableNodeInst) {
ImmutableNodeInst n = (ImmutableNodeInst) d;
for (Iterator<PortProtoId> pit = n.getPortsWithVariables(); pit.hasNext();) {
PortProtoId portId = pit.next();
count += n.getPortInst(portId).getNumVariables();
}
additionalVarKey = NodeInst.NODE_NAME;
if (n.isUsernamed()) {
additionalVarType |= ELIBConstants.VDISPLAY;
additionalTextDescriptor = n.nameDescriptor;
}
additionalVarValue = n.name.toString();
} else if (d instanceof ImmutableArcInst) {
ImmutableArcInst a = (ImmutableArcInst) d;
additionalVarKey = ArcInst.ARC_NAME;
if (a.isUsernamed()) {
additionalVarType |= ELIBConstants.VDISPLAY;
additionalTextDescriptor = a.nameDescriptor;
}
additionalVarValue = a.name.toString();
} else if (d instanceof ImmutableLibrary) {
String[] fontAssociation = createFontAssociation();
if (fontAssociation != null) {
additionalVarKey = Library.FONT_ASSOCIATIONS;
additionalVarType |= ELIBConstants.VISARRAY | (fontAssociation.length << ELIBConstants.VLENGTHSH);
additionalVarValue = fontAssociation;
}
}
if (additionalVarKey != null) {
count++;
}
writeInt("variables: ", count);
if (d instanceof ImmutableCell) {
// write the parameters
for (Iterator<Variable> it = ((ImmutableCell) d).getParameters(); it.hasNext();) {
Variable var = it.next();
writeVariable(null, var);
}
} else if (d instanceof ImmutableIconInst) {
for (Iterator<Variable> it = ((ImmutableIconInst) d).getDefinedParameters(); it.hasNext();) {
Variable var = it.next();
writeVariable(null, var);
}
}
// write the variables
for (Iterator<Variable> it = d.getVariables(); it.hasNext();) {
Variable var = it.next();
writeVariable(null, var);
}
// write variables on PortInsts
if (d instanceof ImmutableNodeInst) {
ImmutableNodeInst n = (ImmutableNodeInst) d;
if (n.hasPortInstVariables()) {
TreeMap<String, ImmutablePortInst> portVars = new TreeMap<String, ImmutablePortInst>(TextUtils.STRING_NUMBER_ORDER);
for (Iterator<PortProtoId> pit = n.getPortsWithVariables(); pit.hasNext();) {
PortProtoId portId = pit.next();
portVars.put(portId.getName(snapshot), n.getPortInst(portId));
}
for (Map.Entry<String, ImmutablePortInst> e : portVars.entrySet()) {
String portName = e.getKey();
ImmutablePortInst p = e.getValue();
for (Iterator<Variable> it = p.getVariables(); it.hasNext();) {
Variable var = it.next();
writeVariable(portName, var);
}
}
}
}
// write the additional variable
if (additionalVarKey != null) {
writeVariableName(additionalVarKey.getName());
writeTextDescriptor(additionalVarType, additionalTextDescriptor);
writeVarValue(additionalVarValue);
}
}
/**
* Method to write an object variables.
* @param portName if this variable is on PortInst, then its name otherwise null.
* @param var variable
*/
void writeVariable(String portName, Variable var) throws IOException {
// create the "type" field
Object varObj = var.getObject();
// special case for "trace" information on NodeInsts
if (varObj instanceof EPoint[]) {
EPoint[] points = (EPoint[]) varObj;
int len = points.length * 2;
Float[] newPoints = new Float[len];
for (int j = 0; j < points.length; j++) {
if (points[j] != null) {
newPoints[j * 2] = new Float(points[j].getLambdaX());
newPoints[j * 2 + 1] = new Float(points[j].getLambdaY());
} else {
newPoints[j * 2] = newPoints[j * 2 + 1] = Float.valueOf(Float.NaN);
}
}
varObj = newPoints;
} else if (varObj instanceof EPoint) {
EPoint p = (EPoint) varObj;
varObj = new Float[]{new Float(p.getLambdaX()), new Float(p.getLambdaY())};
}
int type = ELIBConstants.getVarType(varObj);
if (compatibleWith6 && type == ELIBConstants.VDOUBLE) {
type = ELIBConstants.VFLOAT;
}
assert type != 0;
if (var.isDisplay()) {
type |= ELIBConstants.VDISPLAY;
}
if (varObj instanceof Object[]) {
Object[] objList = (Object[]) varObj;
// This doesn't seem to work properly for trace
// if (objList.length > 0)
type |= ELIBConstants.VISARRAY | (objList.length << ELIBConstants.VLENGTHSH);
}
// Only string variables may have language code bits.
assert (type & ELIBConstants.VTYPE) == ELIBConstants.VSTRING || (type & (ELIBConstants.VCODE1 | ELIBConstants.VCODE2)) == 0;
// write the text descriptor
writeVariableName(diskName(portName, var));
writeTextDescriptor(type, var.getTextDescriptor());
writeVarValue(varObj);
}
/**
* Method to write a set of project preferences.
*/
void writeMeaningPrefs(Object obj) throws IOException {
Setting.Group group = null;
if (obj instanceof Tool) {
group = ((Tool) obj).getProjectSettings();
} else if (obj instanceof Technology) {
group = ((Technology) obj).getProjectSettings();
}
Map<Setting, Object> settings = group.getDiskSettings(snapshot.getSettings());
writeInt("variables: ", settings.size());
for (Map.Entry<Setting, Object> e : settings.entrySet()) {
Setting setting = e.getKey();
Object varObj = e.getValue();
projectSettings.put(setting, varObj);
// create the "type" field
if (varObj instanceof Boolean) {
varObj = Integer.valueOf(((Boolean) varObj).booleanValue() ? 1 : 0);
}
int type = ELIBConstants.getVarType(varObj);
if (compatibleWith6 && type == ELIBConstants.VDOUBLE) {
type = ELIBConstants.VFLOAT;
}
writeVariableName(setting.getPrefName());
writeTextDescriptor(type, null);
writeVarValue(varObj);
}
}
/**
* Method to write the value of variable.
* @param obj value of variable.
*/
void writeVarValue(Object varObj) throws IOException {
if (varObj instanceof Object[]) {
Object[] objList = (Object[]) varObj;
int len = objList.length;
writeBigInteger(len);
for (int i = 0; i < len; i++) {
Object oneObj = objList[i];
putOutVar(oneObj);
}
} else {
putOutVar(varObj);
}
}
/**
* Helper method to write a variable at address "addr" of type "ty".
* Returns zero if OK, negative on memory error, positive if there were
* correctable problems in the write.
*/
private void putOutVar(Object obj) throws IOException {
if (obj instanceof String) {
writeString((String) obj);
return;
}
if (obj instanceof CodeExpression) {
writeString(((CodeExpression) obj).getExpr());
return;
}
if (obj instanceof Double) {
if (compatibleWith6) {
writeFloat(((Double) obj).floatValue());
} else {
writeDouble(((Double) obj).doubleValue());
}
return;
}
if (obj instanceof Float) {
writeFloat(((Float) obj).floatValue());
return;
}
if (obj instanceof Long) {
writeBigInteger(((Long) obj).intValue());
return;
}
if (obj instanceof Integer) {
writeBigInteger(((Integer) obj).intValue());
return;
}
if (obj instanceof Short) {
writeSmallInteger(((Short) obj).shortValue());
return;
}
if (obj instanceof Byte) {
writeByte(((Byte) obj).byteValue());
return;
}
if (obj instanceof Boolean) {
writeByte(((Boolean) obj).booleanValue() ? (byte) 1 : (byte) 0);
return;
}
if (obj instanceof Tool) {
Tool tool = (Tool) obj;
writeBigInteger(tool.getIndex());
return;
}
if (obj instanceof LibId) {
LibId libId = (LibId) obj;
writeString(libId.libName);
return;
}
writeObj(obj);
}
/**
* Method to write a text descriptor (possibly with variable bits).
* Face of text descriptor is mapped according to "faceMap".
* @param varBits variableBits or -1.
* @param td TextDescriptor to write.
*/
private void writeTextDescriptor(int varBits, TextDescriptor td) throws IOException {
int td0;
int td1;
if (td != null) {
td0 = td.lowLevelGet0();
td1 = td.lowLevelGet1();
// Convert font face
if ((td1 & ELIBConstants.VTFACE) != 0) {
int face = (td1 & ELIBConstants.VTFACE) >> ELIBConstants.VTFACESH;
td1 = (td1 & ~ELIBConstants.VTFACE) | (faceMap[face] << ELIBConstants.VTFACESH);
}
} else {
td0 = 0;
td1 = 0;
}
writeTextDescriptor(varBits, td0, td1);
}
/**
* Method to write a text descriptor (possibly with variable bits).
* Face of text descriptor is mapped according to "faceMap".
* @param varBits variableBits or -1.
* @param td0 first word of TextDescriptor to write.
* @param td1 first word of TextDescriptor to write.
*/
void writeTextDescriptor(int varBits, int td0, int td1) throws IOException {
if (varBits != -1) {
writeBigInteger(varBits);
}
writeBigInteger(td0);
writeBigInteger(td1);
}
/**
* Method to write a disk index of Object.
* Index is obtained fron objInfo map.
* @param obj Object to write
*/
void writeObj(Object obj) throws IOException {
int objIndex = -1;
if (obj != null) {
Integer i = objInfo.get(obj);
if (i != null) {
objIndex = i.intValue();
}
}
writeBigInteger(objIndex);
}
/**
* Method to write a coordinate as (4 bytes) integer to the ouput stream.
* @param cellBackup cell to determine scale
* @param keyword keywork fro ReadableDump
* @param gridCoord coordinate in grid units.
*/
private void writeGridCoord(CellBackup cellBackup, String keyword, double gridCoord) throws IOException {
writeGridCoord(cellBackup.cellRevision, keyword, gridCoord);
}
/**
* Method to write a coordinate as (4 bytes) integer to the ouput stream.
* @param cellRevision cell to determine scale
* @param keyword keywork fro ReadableDump
* @param gridCoord coordinate in grid units.
*/
private void writeGridCoord(CellRevision cellRevision, String keyword, double gridCoord) throws IOException {
// int i = gridCoordToElib(cellBackup.d.tech, gridCoord);
Technology tech = snapshot.getTech(cellRevision.d.techId);
writeInt(keyword, gridCoordToElib(tech, gridCoord));
}
int gridCoordToElib(Technology tech, double gridCoord) {
return (int) Math.round(gridCoord * getScale(tech) * 2 / DBMath.GRID);
}
double getScale(TechId techId) {
return getScale(snapshot.getTech(techId));
}
double getScale(Technology tech) {
return tech.isScaleRelevant() || tech == Generic.tech() ? tech.getScale() : irrelevantScale;
}
private Technology.SizeCorrector getSizeCorrector(TechId techId) {
Technology.SizeCorrector corrector = sizeCorrectors.get(techId);
if (corrector == null) {
corrector = techPool.getTech(techId).getSizeCorrector(Version.getVersion(), projectSettings, false, false);
sizeCorrectors.put(techId, corrector);
}
return corrector;
}
/**
* Method to write an integer (4 bytes) to the ouput stream.
* @param keyword keywork fro ReadableDump
* @parma i integer value.
*/
void writeInt(String keyword, int i) throws IOException {
writeBigInteger(i);
}
/**
* Method to write a text into ReadableDump stream.
* @param txt a text to write into ReadableDump stream.
*/
void writeTxt(String txt) throws IOException {
}
/**
* Method to write a disk index of variable name.
* Index is obtained from the nameSpace map.
* @param name Variable Key to write
*/
void writeVariableName(String name) throws IOException {
short varNameIndex = nameSpace.get(name).shortValue();
writeSmallInteger(varNameIndex);
}
// --------------------------------- LOW-LEVEL OUTPUT ---------------------------------
/**
* Method to write a single byte from the input stream and return it.
*/
private void writeByte(byte b)
throws IOException {
dataOutputStream.write(b);
}
/**
* Method to write an integer (4 bytes) from the input stream and return it.
*/
void writeBigInteger(int i)
throws IOException {
dataOutputStream.writeInt(i);
}
/**
* Method to write a float (4 bytes) from the input stream and return it.
*/
private void writeFloat(float f)
throws IOException {
dataOutputStream.writeFloat(f);
}
/**
* Method to write a double (8 bytes) from the input stream and return it.
*/
private void writeDouble(double d)
throws IOException {
dataOutputStream.writeDouble(d);
}
/**
* Method to write an short (2 bytes) from the input stream and return it.
*/
private void writeSmallInteger(short s)
throws IOException {
dataOutputStream.writeShort(s);
}
/**
* Method to write a string from the input stream and return it.
*/
private void writeString(String s)
throws IOException {
// disk and memory match: write the data
int len = s.length();
writeBigInteger(len);
dataOutputStream.write(s.getBytes(), 0, len);
}
}