#!/usr/bin/env python import struct from .gdsPrimitives import * class Gds2reader: """Class to read in a file in GDSII format and populate a layout class with it""" ## Based on info from http://www.rulabinsky.com/cavd/text/chapc.html global offset offset=0 def __init__(self,layoutObject,debugToTerminal = 0): self.fileHandle = None self.layoutObject = layoutObject self.debugToTerminal=debugToTerminal #do we dump debug data to the screen def print64AsBinary(self,number): for index in range(0,64): print((number>>(63-index))&0x1,eol='') print("\n") def stripNonASCII(self,bytestring): string = bytestring.decode('utf-8') return string def ieeeDoubleFromIbmData(self,ibmData): #the GDS double is in IBM 370 format like this: #(1)sign (7)exponent (56)mantissa #exponent is excess 64, mantissa has no implied 1 #a normal IEEE double is like this: #(1)sign (11)exponent (52)mantissa data = struct.unpack('>q',ibmData)[0] sign = (data >> 63)&0x01 exponent = (data >> 56) & 0x7f mantissa = data<<8 #chop off sign and exponent if mantissa == 0: newFloat = 0.0 else: exponent = ((exponent-64)*4)+1023 #convert to double exponent #re normalize while mantissa & 0x8000000000000000 == 0: mantissa<<=1 exponent-=1 mantissa<<=1 #remove the assumed high bit exponent-=1 #check for underflow error -- should handle these properly! if(exponent<=0): print("Underflow Error") elif(exponent == 2047): print("Overflow Error") #re assemble newFloat=(sign<<63)|(exponent<<52)|((mantissa>>12)&0xfffffffffffff) asciiDouble = struct.pack('>q',newFloat) #convert back to double newFloat = struct.unpack('>d',asciiDouble)[0] return newFloat def ieeeFloatCheck(self,aFloat): asciiDouble = struct.pack('>d',aFloat) data = struct.unpack('>q',asciiDouble)[0] sign = data >> 63 exponent = ((data >> 52) & 0x7ff)-1023 # BINWU: Cleanup #print(exponent+1023) mantissa = data << 12 #chop off sign and exponent # BINWU: Cleanup #self.print64AsBinary((sign<<63)|((exponent+1023)<<52)|(mantissa>>12)) asciiDouble = struct.pack('>q',(sign<<63)|(exponent+1023<<52)|(mantissa>>12)) newFloat = struct.unpack('>d',asciiDouble)[0] print("Check:"+str(newFloat)) def readNextRecord(self): global offset recordLengthAscii = self.fileHandle.read(2) #first 2 bytes tell us the length of the record if len(recordLengthAscii)==0: return recordLength = struct.unpack(">h",recordLengthAscii) #gives us a tuple with a short int inside offset_int = int(recordLength[0]) # extract length offset += offset_int # count offset #print(offset) #print out the record numbers for de-bugging record = self.fileHandle.read(recordLength[0]-2) #read the rest of it (first 2 bytes were already read) return record def readHeader(self): self.layoutObject.info.clear() ## Header record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x00\x02' and len(record)==4): gdsVersion = struct.unpack(">h",record[2:4])[0] self.layoutObject.info["gdsVersion"]=gdsVersion if(self.debugToTerminal==1): print("GDS II Version "+str(gdsVersion)) else: print("Invalid GDSII Header") return -1 #read records until we hit the UNITS section... this is the last part of the header while 1: record = self.readNextRecord() idBits = record[0:2] ## Modified Date if idBits==b'\x01\x02' and len(record)==26: modYear = struct.unpack(">h",record[2:4])[0] modMonth = struct.unpack(">h",record[4:6])[0] modDay = struct.unpack(">h",record[6:8])[0] modHour = struct.unpack(">h",record[8:10])[0] modMinute = struct.unpack(">h",record[10:12])[0] modSecond = struct.unpack(">h",record[12:14])[0] lastAccessYear = struct.unpack(">h",record[14:16])[0] lastAccessMonth = struct.unpack(">h",record[16:18])[0] lastAccessDay = struct.unpack(">h",record[18:20])[0] lastAccessHour = struct.unpack(">h",record[20:22])[0] lastAccessMinute = struct.unpack(">h",record[22:24])[0] lastAccessSecond = struct.unpack(">h",record[24:26])[0] self.layoutObject.info["dates"]=(modYear,modMonth,modDay,modHour,modMinute,modSecond,\ lastAccessYear,lastAccessMonth,lastAccessDay,lastAccessHour,lastAccessMinute,lastAccessSecond) if(self.debugToTerminal==1): print("Date Modified:"+str(modYear)+","+str(modMonth)+","+str(modDay)+","+str(modHour)+","+str(modMinute)+","+str(modSecond)) print("Date Last Accessed:"+str(lastAccessYear)+","+str(lastAccessMonth)+","+str(lastAccessDay)+\ ","+str(lastAccessHour)+","+str(lastAccessMinute)+","+str(lastAccessSecond)) ## LibraryName elif(idBits==b'\x02\x06'): libraryName = record[2::].decode("utf-8") self.layoutObject.info["libraryName"]=libraryName if(self.debugToTerminal==1): print("Library: "+libraryName) ## reference libraries elif(idBits==b'\x1F\x06'): referenceLibraryA = record[2:46] referenceLibraryB = record[47:91] self.layoutObject.info["referenceLibraries"]=(referenceLibraryA,referenceLibraryB) if(self.debugToTerminal==1): print( "Reference Libraries:"+referenceLibraryA+","+referenceLibraryB) elif(idBits==b'\x20\x06'): fontA = record[2:45] fontB = record[46:89] fontC = record[90:133] fontD = record[134:177] self.layoutObject.info["fonts"]=(fontA,fontB,fontC,fontD) if(self.debugToTerminal==1): print("Fonts:"+fontA+","+fontB+","+fontC+","+fontD) elif(idBits==b'\x23\x06'): attributeTable = record[2:45] self.layoutObject.info["attributeTable"]=attributeTable if(self.debugToTerminal==1): print("Attributes:"+attributeTable) elif(idBits==b'\x22\x02'): generations = struct.unpack(">h",record[2]+record[3]) self.layoutObject.info["generations"]=generations if(self.debugToTerminal==1): print("Generations:"+generations ) elif(idBits==b'\x36\x02'): fileFormat = struct.unpack(">h",record[2]+record[3]) self.layoutObject.info["fileFormat"]=fileFormat if(self.debugToTerminal==1): print("File Format:"+fileFormat) elif(idBits==b'\x37\x06'): mask = record[2::] self.layoutObject.info["mask"] = mask if(self.debugToTerminal==1): print("Mask: "+mask) elif(idBits==b'\x03\x05'): #this is also wrong b/c python doesn't natively have an 8 byte float userUnits=self.ieeeDoubleFromIbmData(record[2:10]) dbUnits=self.ieeeDoubleFromIbmData(record[10:18]) self.layoutObject.info["units"] = (userUnits,dbUnits) if(self.debugToTerminal==1): print("Units: 1 user unit="+str(userUnits)+" database units, 1 database unit="+str(dbUnits)+" meters.") break; if(self.debugToTerminal==1): print("End of GDSII Header Found") return 1 def readBoundary(self): ##reads in a boundary type structure = a filled polygon if(self.debugToTerminal==1): print("\t\t\tBeginBoundary") thisBoundary=GdsBoundary() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisBoundary.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisBoundary.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x0D\x02'): #Layer drawingLayer = struct.unpack(">h",record[2:4])[0] thisBoundary.drawingLayer=drawingLayer if drawingLayer not in self.layoutObject.layerNumbersInUse: self.layoutObject.layerNumbersInUse += [drawingLayer] if(self.debugToTerminal==1): print("\t\tDrawing Layer: "+str(drawingLayer)) elif(idBits==b'\x0E\x02'): #Purpose DATATYPE purposeLayer = struct.unpack(">h",record[2:4])[0] thisBoundary.purposeLayer=purposeLayer if(self.debugToTerminal==1): print("\t\tPurpose Layer: "+str(purposeLayer)) elif(idBits==b'\x10\x03'): #XY Data Points numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each thisBoundary.coordinates=[] for index in range(2,numDataPoints+2,8): #incorporate the 2 byte offset x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisBoundary.coordinates+=[(x,y)] if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndBoundary") break; return thisBoundary def readPath(self): #reads in a path structure if(self.debugToTerminal==1): print("\t\t\tBeginPath") thisPath=GdsPath() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisPath.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisPath.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x0D\x02'): #Layer drawingLayer = struct.unpack(">h",record[2:4])[0] thisPath.drawingLayer=drawingLayer if drawingLayer not in self.layoutObject.layerNumbersInUse: self.layoutObject.layerNumbersInUse += [drawingLayer] if(self.debugToTerminal==1): print("\t\t\tDrawing Layer: "+str(drawingLayer)) elif(idBits==b'\x16\x02'): #Purpose purposeLayer = struct.unpack(">h",record[2:4])[0] thisPath.purposeLayer=purposeLayer if(self.debugToTerminal==1): print("\t\tPurpose Layer: "+str(purposeLayer)) elif(idBits==b'\x21\x02'): #Path type pathType = struct.unpack(">h",record[2:4])[0] thisPath.pathType=pathType if(self.debugToTerminal==1): print("\t\t\tPath Type: "+str(pathType)) elif(idBits==b'\x0E\x02'): #Data type dataType = struct.unpack(">h",record[2:4])[0] thisPath.dataType=dataType if(self.debugToTerminal==1): print("\t\t\tData Type: "+str(dataType)) elif(idBits==b'\x0F\x03'): #Path width pathWidth = struct.unpack(">i",record[2:6])[0] thisPath.pathWidth=pathWidth if(self.debugToTerminal==1): print("\t\t\tPath Width: "+str(pathWidth)) elif(idBits==b'\x10\x03'): #XY Data Points numDataPoints = len(record)-2 #packed nas XY coordinates 4 bytes each thisPath.coordinates=[] for index in range(2,numDataPoints+2,8): #incorporate the 2 byte offset x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisPath.coordinates+=[(x,y)] if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndPath") break; return thisPath def readSref(self): #reads in a reference to another structure if(self.debugToTerminal==1): print("\t\t\tBeginSref") thisSref=GdsSref() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisSref.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisSref.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x12\x06'): #Reference Name sName = self.stripNonASCII(record[2::]) thisSref.sName=sName.rstrip() if(self.debugToTerminal==1): print("\t\tReference Name:"+sName) elif(idBits==b'\x1A\x01'): #Transformation transFlags = struct.unpack(">H",record[2:4])[0] mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy rotateFlag = bool(transFlags&0x0002) magnifyFlag = bool(transFlags&0x0004) thisSref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag] if(self.debugToTerminal==1): print("\t\t\tMirror X:"+str(mirrorFlag)) print( "\t\t\tRotate:"+str(rotateFlag)) print("\t\t\tMagnify:"+str(magnifyFlag)) elif(idBits==b'\x1B\x05'): #Magnify magFactor=self.ieeeDoubleFromIbmData(record[2:10]) thisSref.magFactor=magFactor if(self.debugToTerminal==1): print("\t\t\tMagnification:"+str(magFactor)) elif(idBits==b'\x1C\x05'): #Rotate Angle rotateAngle=self.ieeeDoubleFromIbmData(record[2:10]) thisSref.rotateAngle=rotateAngle if(self.debugToTerminal==1): print("\t\t\tRotate Angle (CCW):"+str(rotateAngle)) elif(idBits==b'\x10\x03'): #XY Data Points index=2 x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisSref.coordinates=(x,y) if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndSref") break; return thisSref def readAref(self): #an array of references if(self.debugToTerminal==1): print("\t\t\tBeginAref") thisAref = GdsAref() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisAref.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisAref.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x12\x06'): #Reference Name aName = record[2::] thisAref.aName=aName if(self.debugToTerminal==1): print("\t\tReference Name:"+aName) elif(idBits==b'\x1A\x01'): #Transformation transFlags = struct.unpack(">H",record[2:4])[0] mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy rotateFlag = bool(transFlags&0x0002) magnifyFlag = bool(transFlags&0x0004) thisAref.transFlags=[mirrorFlag,magnifyFlag,rotateFlag] if(self.debugToTerminal==1): print("\t\t\tMirror X:"+str(mirrorFlag)) print("\t\t\tRotate:"+str(rotateFlag)) print("\t\t\tMagnify:"+str(magnifyFlag)) elif(idBits==b'\x1B\x05'): #Magnify magFactor=self.ieeeDoubleFromIbmData(record[2:10]) thisAref.magFactor=magFactor if(self.debugToTerminal==1): print("\t\t\tMagnification:"+str(magFactor)) elif(idBits==b'\x1C\x05'): #Rotate Angle rotateAngle=self.ieeeDoubleFromIbmData(record[2:10]) thisAref.rotateAngle=rotateAngle if(self.debugToTerminal==1): print("\t\t\tRotate Angle (CCW):"+str(rotateAngle)) elif(idBits==b'\x10\x03'): #XY Data Points index=2 topLeftX=struct.unpack(">i",record[index:index+4])[0] topLeftY=struct.unpack(">i",record[index+4:index+8])[0] rightMostX=struct.unpack(">i",record[index+8:index+12])[0] bottomMostY=struct.unpack(">i",record[index+12:index+16])[0] thisAref.coordinates=[(topLeftX,topLeftY),(rightMostX,topLeftY),(topLeftX,bottomMostY)] if(self.debugToTerminal==1): print("\t\t\tTop Left Point: "+str(topLeftX)+","+str(topLeftY)) print("\t\t\t\tArray Width: "+str(rightMostX-topLeftX)) print("\t\t\t\tArray Height: "+str(topLeftY-bottomMostY)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndAref") break; return thisAref def readText(self): if(self.debugToTerminal==1): print("\t\t\tBeginText") thisText=GdsText() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisText.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisText.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x0D\x02'): #Layer drawingLayer = struct.unpack(">h",record[2:4])[0] thisText.drawingLayer=drawingLayer if drawingLayer not in self.layoutObject.layerNumbersInUse: self.layoutObject.layerNumbersInUse += [drawingLayer] if(self.debugToTerminal==1): print("\t\tDrawing Layer: "+str(drawingLayer)) elif(idBits==b'\x16\x02'): #Purpose TEXTTYPE purposeLayer = struct.unpack(">h",record[2:4])[0] thisText.purposeLayer=purposeLayer if(self.debugToTerminal==1): print("\t\tPurpose Layer: "+str(purposeLayer)) elif(idBits==b'\x1A\x01'): #Transformation transFlags = struct.unpack(">H",record[2:4])[0] mirrorFlag = bool(transFlags&0x8000) ##these flags are a bit sketchy rotateFlag = bool(transFlags&0x0002) magnifyFlag = bool(transFlags&0x0004) thisText.transFlags=[mirrorFlag,magnifyFlag,rotateFlag] if(self.debugToTerminal==1): print("\t\t\tMirror X:"+str(mirrorFlag)) print("\t\t\tRotate:"+str(rotateFlag)) print("\t\t\tMagnify:"+str(magnifyFlag)) elif(idBits==b'\x1B\x05'): #Magnify magFactor=self.ieeeDoubleFromIbmData(record[2:10]) thisText.magFactor=magFactor if(self.debugToTerminal==1): print("\t\t\tMagnification:"+str(magFactor)) elif(idBits==b'\x1C\x05'): #Rotate Angle rotateAngle=self.ieeeDoubleFromIbmData(record[2:10]) thisText.rotateAngle=rotateAngle if(self.debugToTerminal==1): print("\t\t\tRotate Angle (CCW):"+str(rotateAngle)) elif(idBits==b'\x21\x02'): #Path type pathType = struct.unpack(">h",record[2:4])[0] thisText.pathType=pathType if(self.debugToTerminal==1): print("\t\t\tPath Type: "+str(pathType)) elif(idBits==b'\x0F\x03'): #Path width pathWidth = struct.unpack(">i",record[2:6])[0] thisText.pathWidth=pathWidth if(self.debugToTerminal==1): print("\t\t\tPath Width: "+str(pathWidth)) elif(idBits==b'\x1A\x01'): #Text Presentation presentationFlags = struct.unpack(">H",record[2:4])[0] font = (presentationFlags&0x0030)>>4 ##these flags are a bit sketchy verticalFlags = (presentationFlags&0x000C) horizontalFlags = (presentationFlags&0x0003) thisText.presentationFlags=(font,verticalFlags,horizontalFlags) if(self.debugToTerminal==1): print("\t\t\tFont:"+str(font)) if(verticalFlags==0): if(self.debugToTerminal==1): print("\t\t\tVertical: Top") elif(verticalFlags==1): if(self.debugToTerminal==1): print("\t\t\tVertical: Middle") elif(verticalFlags==2): if(self.debugToTerminal==1): print("\t\t\tVertical: Bottom") if(horizontalFlags==0): if(self.debugToTerminal==1): print("\t\t\tHorizontal: Left") elif(horizontalFlags==1): if(self.debugToTerminal==1): print("\t\t\tHorizontal: Center") elif(horizontalFlags==2): if(self.debugToTerminal==1): print("\t\t\tHorizontal: Right") elif(idBits==b'\x10\x03'): #XY Data Points index=2 x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisText.coordinates=[(x,y)] if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x19\x06'): #Text String - also the last record in this element textString = record[2::].decode('utf-8') thisText.textString=textString if(self.debugToTerminal==1): print("\t\t\tText String: "+textString) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndText") break; return thisText def readNode(self): if(self.debugToTerminal==1): print("\t\t\tBeginNode") ##reads in a node type structure = an electrical net thisNode = GdsNode() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4])[0] thisNode.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisNode.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x0D\x02'): #Layer drawingLayer = struct.unpack(">h",record[2:4])[0] thisNode.drawingLayer=drawingLayer if drawingLayer not in self.layoutObject.layerNumbersInUse: self.layoutObject.layerNumbersInUse += [drawingLayer] if(self.debugToTerminal==1): print("\t\tDrawing Layer: "+str(drawingLayer)) elif(idBits==b'\x2A\x02'): #Node Type nodeType = struct.unpack(">h",record[2:4])[0] thisNode.nodeType=nodeType if(self.debugToTerminal==1): print("\t\tNode Type: "+str(nodeType)) elif(idBits==b'\x10\x03'): #XY Data Points numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each thisNode.coordinates=[] for index in range(2,numDataPoints+2,8): #incorporate the 2 byte offset x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisNode.coordinates+=[(x,y)] if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndNode") break; return thisNode def readBox(self): if(self.debugToTerminal==1): print("\t\t\tBeginBox") ##reads in a gds BOX structure thisBox = GdsBox() while 1: record = self.readNextRecord() idBits = record[0:2] if(idBits==b'\x26\x01'): #ELFLAGS elementFlags = struct.unpack(">h",record[2:4]) thisBox.elementFlags=elementFlags if(self.debugToTerminal==1): print("\t\tElement Flags: "+str(elementFlags)) elif(idBits==b'\x2F\x03'): #PLEX plex = struct.unpack(">i",record[2:6])[0] thisBox.plex=plex if(self.debugToTerminal==1): print("\t\tPLEX: "+str(plex)) elif(idBits==b'\x0D\x02'): #Layer drawingLayer = struct.unpack(">h",record[2:4])[0] thisBox.drawingLayer=drawingLayer if drawingLayer not in self.layoutObject.layerNumbersInUse: self.layoutObject.layerNumbersInUse += [drawingLayer] if(self.debugToTerminal==1): print("\t\tDrawing Layer: "+str(drawingLayer)) elif(idBits==b'\x16\x02'): #Purpose TEXTYPE purposeLayer = struct.unpack(">h",record[2:4])[0] thisBox.purposeLayer=purposeLayer if(self.debugToTerminal==1): print("\t\tPurpose Layer: "+str(purposeLayer)) elif(idBits==b'\x2D\x00'): #Box boxValue = struct.unpack(">h",record[2:4])[0] thisBox.boxValue=boxValue if(self.debugToTerminal==1): print("\t\tBox Value: "+str(boxValue)) elif(idBits==b'\x10\x03'): #XY Data Points that form a closed box numDataPoints = len(record)-2 #packed as XY coordinates 4 bytes each thisBox.coordinates=[] for index in range(2,numDataPoints+2,8): #incorporate the 2 byte offset x=struct.unpack(">i",record[index:index+4])[0] y=struct.unpack(">i",record[index+4:index+8])[0] thisBox.coordinates+=[(x,y)] if(self.debugToTerminal==1): print("\t\t\tXY Point: "+str(x)+","+str(y)) elif(idBits==b'\x11\x00'): #End Of Element if(self.debugToTerminal==1): print("\t\t\tEndBox") break; return thisBox def readNextStructure(self): thisStructure = GdsStructure() record = self.readNextRecord() idBits = record[0:2] # Begin structure if(idBits==b'\x05\x02' and len(record)==26): createYear = struct.unpack(">h",record[2:4])[0] createMonth = struct.unpack(">h",record[4:6])[0] createDay = struct.unpack(">h",record[6:8])[0] createHour = struct.unpack(">h",record[8:10])[0] createMinute = struct.unpack(">h",record[10:12])[0] createSecond = struct.unpack(">h",record[12:14])[0] modYear = struct.unpack(">h",record[14:16])[0] modMonth = struct.unpack(">h",record[16:18])[0] modDay = struct.unpack(">h",record[18:20])[0] modHour = struct.unpack(">h",record[20:22])[0] modMinute = struct.unpack(">h",record[22:24])[0] modSecond = struct.unpack(">h",record[24:26])[0] thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond) thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond) if(self.debugToTerminal==1): print("Date Created:"+str(createYear)+","+str(createMonth)+","+str(createDay)+\ ","+str(createHour)+","+str(createMinute)+","+str(createSecond)) print("Date Modified:"+str(modYear)+","+str(modMonth)+","+str(modDay)+","+str(modHour)+","+str(modMinute)+","+str(modSecond)) else: #means we have hit the last structure, so return the record #to whoever called us to do something with it return record while 1: record = self.readNextRecord() idBits = record[0:2] if idBits==b'\x07\x00': break; #we've reached the end of the structure elif(idBits==b'\x06\x06'): structName = self.stripNonASCII(record[2::]) thisStructure.name = structName if(self.debugToTerminal==1): print("\tStructure Name: "+structName) elif(idBits==b'\x08\x00'): thisStructure.boundaries+=[self.readBoundary()] elif(idBits==b'\x09\x00'): thisStructure.paths+=[self.readPath()] elif(idBits==b'\x0A\x00'): thisStructure.srefs+=[self.readSref()] elif(idBits==b'\x0B\x00'): thisStructure.arefs+=[self.readAref()] elif(idBits==b'\x0C\x00'): thisStructure.texts+=[self.readText()] elif(idBits==b'\x15\x00'): thisStructure.nodes+=[self.readNode()] elif(idBits==b'\x2E\x02'): thisStructure.boxes+=[self.readBox()] if(self.debugToTerminal==1): print("\tEnd of Structure.") self.layoutObject.structures[structName]=thisStructure #add this structure to the layout object return 1 def readGds2(self): if(self.readHeader()): #did the header read ok? record = self.readNextStructure() while(record == 1): record = self.readNextStructure() #now we have fallen out of the while, which means we are out of structures #so test for end of library if(len(record)>1): idBits = record[0:2] if idBits==b'\x04\x00': #we've reached the end of the library if(self.debugToTerminal==1): print("End of GDS Library.") else: print("There was an error reading the structure list.") else: print("There was an error parsing the GDS header. Aborting...") def loadFromFile(self, fileName): self.fileHandle = open(fileName,"rb") self.readGds2() self.fileHandle.close() self.layoutObject.initialize() ############################################## def findStruct(self,fileName,findStructName): #print("find struct") self.fileHandle = open(fileName,"rb") self.debugToTerminal=0 if(self.readHeader()): #did the header read ok? record = self.findStruct_readNextStruct(findStructName) while(record == 1): record = self.findStruct_readNextStruct(findStructName) #now we have fallen out of the while, which means we are out of structures #so test for end of library else: print("There was an error parsing the GDS header. Aborting...") self.fileHandle.close() #print("End the search of",findStructName) #self.layoutObject.initialize() return record def findStruct_readNextStruct(self,findStructName): self.debugToTerminal=0 thisStructure = GdsStructure() record = self.readNextRecord() idBits = record[0:2] if(idBits==('\x05','\x02') and len(record)==26): createYear = struct.unpack(">h",record[2]+record[3])[0] createMonth = struct.unpack(">h",record[4]+record[5])[0] createDay = struct.unpack(">h",record[6]+record[7])[0] createHour = struct.unpack(">h",record[8]+record[9])[0] createMinute = struct.unpack(">h",record[10]+record[11])[0] createSecond = struct.unpack(">h",record[12]+record[13])[0] modYear = struct.unpack(">h",record[14]+record[15])[0] modMonth = struct.unpack(">h",record[16]+record[17])[0] modDay = struct.unpack(">h",record[18]+record[19])[0] modHour = struct.unpack(">h",record[20]+record[21])[0] modMinute = struct.unpack(">h",record[22]+record[23])[0] modSecond = struct.unpack(">h",record[24]+record[25])[0] thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond) thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond) else: #means we have hit the last structure, so return the record #to whoever called us to do something with it return record wantedStruct=0 while 1: record = self.readNextRecord() idBits = record[0:2] if idBits==('\x07','\x00'): break; #we've reached the end of the structure elif(idBits==('\x06','\x06')): structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() thisStructure.name = structName if(findStructName==thisStructure.name): wantedStruct=1 if(self.debugToTerminal==1): print("\tStructure Name: "+structName) elif(idBits==('\x08','\x00')): thisStructure.boundaries+=[self.readBoundary()] elif(idBits==('\x09','\x00')): thisStructure.paths+=[self.readPath()] elif(idBits==('\x0A','\x00')): thisStructure.srefs+=[self.readSref()] elif(idBits==('\x0B','\x00')): thisStructure.arefs+=[self.readAref()] elif(idBits==('\x0C','\x00')): thisStructure.texts+=[self.readText()] elif(idBits==('\x15','\x00')): thisStructure.nodes+=[self.readNode()] elif(idBits==('\x2E','\x02')): thisStructure.boxes+=[self.readBox()] if(self.debugToTerminal==1): print("\tEnd of Structure.") self.layoutObject.structures[structName]=thisStructure #add this structure to the layout object if(wantedStruct == 0): return 1 else: #print("\tDone with collectting bound. Return") return [0,thisStructure.boundaries] def findLabel(self,fileName,findLabelName): #print("find Label") self.fileHandle = open(fileName,"rb") self.debugToTerminal=0 if(self.readHeader()): #did the header read ok? record = self.findLabel_readNextStruct(findLabelName) while(record == 1): record = self.findLabel_readNextStruct(findLabelName) #now we have fallen out of the while, which means we are out of structures #so test for end of library else: print("There was an error parsing the GDS header. Aborting...") self.fileHandle.close() #print("End the search of",findStructName) #self.layoutObject.initialize() return record def findLabel_readNextStruct(self,findLabelName): self.debugToTerminal=0 thisStructure = GdsStructure() record = self.readNextRecord() idBits = record[0:2] if(idBits==('\x05','\x02') and len(record)==26): createYear = struct.unpack(">h",record[2]+record[3])[0] createMonth = struct.unpack(">h",record[4]+record[5])[0] createDay = struct.unpack(">h",record[6]+record[7])[0] createHour = struct.unpack(">h",record[8]+record[9])[0] createMinute = struct.unpack(">h",record[10]+record[11])[0] createSecond = struct.unpack(">h",record[12]+record[13])[0] modYear = struct.unpack(">h",record[14]+record[15])[0] modMonth = struct.unpack(">h",record[16]+record[17])[0] modDay = struct.unpack(">h",record[18]+record[19])[0] modHour = struct.unpack(">h",record[20]+record[21])[0] modMinute = struct.unpack(">h",record[22]+record[23])[0] modSecond = struct.unpack(">h",record[24]+record[25])[0] thisStructure.createDate=(createYear,createMonth,createDay,createHour,createMinute,createSecond) thisStructure.modDate=(modYear,modMonth,modDay,modHour,modMinute,modSecond) else: #means we have hit the last structure, so return the record #to whoever called us to do something with it return record wantedLabel=0 wantedtexts=[GdsText()] while 1: record = self.readNextRecord() idBits = record[0:2] if idBits==('\x07','\x00'): break; #we've reached the end of the structure elif(idBits==('\x06','\x06')): structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() thisStructure.name = structName if(self.debugToTerminal==1): print("\tStructure Name: "+structName) elif(idBits==('\x08','\x00')): thisStructure.boundaries+=[self.readBoundary()] elif(idBits==('\x09','\x00')): thisStructure.paths+=[self.readPath()] elif(idBits==('\x0A','\x00')): thisStructure.srefs+=[self.readSref()] elif(idBits==('\x0B','\x00')): thisStructure.arefs+=[self.readAref()] elif(idBits==('\x0C','\x00')): label=self.readText() #Be careful: label.textString contains one space string in it. Delete that one before use it if( findLabelName == label.textString[0:(len(label.textString)-1)] ): wantedLabel=1 wantedtexts+=[label] thisStructure.texts+=[label] if(self.debugToTerminal == 1): print(label.textString[0:(len(label.textString)-1)],findLabelName,( findLabelName == label.textString[0:(len(label.textString)-1)] )) elif(idBits==('\x15','\x00')): thisStructure.nodes+=[self.readNode()] elif(idBits==('\x2E','\x02')): thisStructure.boxes+=[self.readBox()] if(self.debugToTerminal==1): print("\tEnd of Structure.") self.layoutObject.structures[structName]=thisStructure #add this structure to the layout object if(wantedLabel == 0): return 1 else: #print("\tDone with collectting bound. Return") return [0,wantedtexts]