1#! /usr/bin/python 2# -*- coding: utf-8 -*- 3# Copyright © 2010 Eugeniy Meshcheryakov <eugen@debian.org> 4# This file is licensed under GNU Lesser General Public License version 3 or later. 5from __future__ import print_function 6from gdsii.library import Library 7from gdsii import elements 8import sys 9from yaml.dumper import Dumper 10from yaml import events 11 12# standard tags 13STR = 'tag:yaml.org,2002:str' 14TIMESTAMP = 'tag:yaml.org,2002:timestamp' 15FLOAT = 'tag:yaml.org,2002:float' 16INT = 'tag:yaml.org,2002:int' 17SEQ = 'tag:yaml.org,2002:seq' 18MAP = 'tag:yaml.org,2002:map' 19 20# non-standard tags 21LIBRARY = 'tag:gdsii,2010:library' 22STRUCTURE = 'tag:gdsii,2010:structure' 23 24BOUNDARY = 'tag:gdsii,2010:element:boundary' 25PATH = 'tag:gdsii,2010:element:path' 26SREF = 'tag:gdsii,2010:element:sref' 27AREF = 'tag:gdsii,2010:element:aref' 28TEXT = 'tag:gdsii,2010:element:text' 29NODE = 'tag:gdsii,2010:element:node' 30BOX = 'tag:gdsii,2010:element:box' 31 32def emit_string(dumper, prop, tag, value): 33 dumper.emit(events.ScalarEvent(None, STR, (True, False), prop)) 34 dumper.emit(events.ScalarEvent(None, tag, (True, False), value)) 35 36def start_named_seq(dumper, name): 37 dumper.emit(events.ScalarEvent(None, STR, (True, False), name)) 38 dumper.emit(events.SequenceStartEvent(None, SEQ, True)) 39 40def end_named_seq(dumper): 41 dumper.emit(events.SequenceEndEvent()) 42 43def simple_dumper(name, tag): 44 def dump_fn(dumper, obj): 45 value = getattr(obj, name) 46 emit_string(dumper, name, tag, str(value)) 47 return dump_fn 48 49def simple_string_dumper(name): 50 def dump_fn(dumper, obj): 51 value = getattr(obj, name) 52 emit_string(dumper, name, STR, value.decode()) 53 return dump_fn 54 55def timestamp_dumper(name): 56 def dump_fn(dumper, obj): 57 value = getattr(obj, name) 58 emit_string(dumper, name, TIMESTAMP, value.isoformat(' ')) 59 return dump_fn 60 61def optional_dumper(name, tag): 62 def dump_fn(dumper, obj): 63 try: 64 value = getattr(obj, name) 65 except AttributeError: 66 value = None 67 if value is not None: 68 emit_string(dumper, name, tag, str(value)) 69 return dump_fn 70 71def optional_flags_dumper(name, tag): 72 def dump_fn(dumper, obj): 73 try: 74 value = getattr(obj, name) 75 except AttributeError: 76 value = None 77 if value is not None: 78 emit_string(dumper, name, tag, '0x%x'%value) 79 return dump_fn 80 81def xy_dumper(name): 82 def dump_fn(dumper, obj): 83 points = getattr(obj, name) 84 start_named_seq(dumper, name) 85 for point in points: 86 dumper.emit(events.SequenceStartEvent(None, SEQ, True, flow_style=True)) 87 dumper.emit(events.ScalarEvent(None, INT, (True, False), str(point[0]))) 88 dumper.emit(events.ScalarEvent(None, INT, (True, False), str(point[1]))) 89 dumper.emit(events.SequenceEndEvent()) 90 end_named_seq(dumper) 91 return dump_fn 92 93def properties_dumper(name): 94 def dump_fn(dumper, obj): 95 properties = getattr(obj, name) 96 if (properties): 97 start_named_seq(dumper, name) 98 for (prop, value) in properties: 99 dumper.emit(events.MappingStartEvent(None, MAP, True)) 100 dumper.emit(events.ScalarEvent(None, INT, (True, False), str(prop))) 101 dumper.emit(events.ScalarEvent(None, STR, (True, False), value.decode())) 102 dumper.emit(events.MappingEndEvent()) 103 end_named_seq(dumper) 104 return dump_fn 105 106def strans_dumper(name): 107 my_dumper = optional_flags_dumper('strans', INT) 108 mag = optional_dumper('mag', FLOAT) 109 angle = optional_dumper('angle', FLOAT) 110 def dump_fn(dumper, obj): 111 try: 112 value = getattr(obj, name) 113 except AttributeError: 114 value = None 115 if value is not None: 116 my_dumper(dumper, obj) 117 mag(dumper, obj) 118 angle(dumper, obj) 119 return dump_fn 120 121elflags = optional_flags_dumper('elflags', INT) 122plex = optional_dumper('plex', INT) 123layer = simple_dumper('layer', INT) 124data_type = simple_dumper('data_type', INT) 125path_type = optional_dumper('path_type', INT) 126width = optional_dumper('width', INT) 127bgn_extn = optional_dumper('bgn_extn', INT) 128end_extn = optional_dumper('end_extn', INT) 129struct_name = simple_string_dumper('struct_name') 130strans = strans_dumper('strans') 131cols = simple_dumper('cols', INT) 132rows = simple_dumper('rows', INT) 133text_type = optional_dumper('text_type', INT) 134presentation = optional_flags_dumper('presentation', INT) 135string = simple_string_dumper('string') 136node_type = simple_dumper('node_type', INT) 137box_type = simple_dumper('box_type', INT) 138xy = xy_dumper('xy') 139properties = properties_dumper('properties') 140 141DUMPERS = ( 142 (elements.Boundary, BOUNDARY, (elflags, plex, layer, data_type, xy, properties)), 143 (elements.Path, PATH, (elflags, plex, layer, data_type, path_type, width, bgn_extn, end_extn, xy, properties)), 144 (elements.SRef, SREF, (elflags, plex, struct_name, strans, xy, properties)), 145 (elements.ARef, AREF, (elflags, plex, struct_name, strans, cols, rows, xy, properties)), 146 (elements.Text, TEXT, (elflags, plex, layer, text_type, presentation, path_type, width, strans, xy, string, properties)), 147 (elements.Node, NODE, (elflags, plex, layer, node_type, xy)), 148 (elements.Box, BOX, (elflags, plex, layer, box_type, xy, properties)) 149) 150 151def dump_element(dumper, elem): 152 for rec in DUMPERS: 153 if isinstance(elem, rec[0]): 154 tag = rec[1] 155 dumpers = rec[2] 156 dumper.emit(events.MappingStartEvent(None, tag, False)) 157 for fn in dumpers: 158 fn(dumper, elem) 159 dumper.emit(events.MappingEndEvent()) 160 break 161 else: 162 raise Exception('Unsupported element: %s' % str(elem)) 163 164name = simple_string_dumper('name') 165mod_time = timestamp_dumper('mod_time') 166acc_time = timestamp_dumper('acc_time') 167strclass = optional_dumper('strclass', INT) 168 169def dump_structure(dumper, struc): 170 dumper.emit(events.MappingStartEvent(None, STRUCTURE, False)) 171 name(dumper, struc) 172 mod_time(dumper, struc) 173 acc_time(dumper, struc) 174 strclass(dumper, struc) 175 start_named_seq(dumper, 'elements') 176 for elem in struc: 177 dump_element(dumper, elem) 178 end_named_seq(dumper) 179 dumper.emit(events.MappingEndEvent()) 180 181physical_unit = simple_dumper('physical_unit', FLOAT) 182logical_unit = simple_dumper('logical_unit', FLOAT) 183libdirsize = optional_dumper('libdirsize', INT) 184 185def dump_library(dumper, lib): 186 dumper.emit(events.StreamStartEvent(encoding='utf-8')) 187 dumper.emit(events.DocumentStartEvent(explicit=False)) 188 189 dumper.emit(events.MappingStartEvent(None, LIBRARY, False)) 190 emit_string(dumper, 'version', INT, '0x%x'%lib.version) 191 name(dumper, lib) 192 mod_time(dumper, lib) 193 acc_time(dumper, lib) 194 libdirsize(dumper, lib) 195 # TODO 196 physical_unit(dumper, lib) 197 logical_unit(dumper, lib) 198 start_named_seq(dumper, 'structures') 199 for struc in lib: 200 dump_structure(dumper, struc) 201 end_named_seq(dumper) 202 dumper.emit(events.MappingEndEvent()) 203 204 dumper.emit(events.DocumentEndEvent(explicit=False)) 205 dumper.emit(events.StreamEndEvent()) 206 207def main(name): 208 with open(name, 'rb') as a_file: 209 lib = Library.load(stream=a_file) 210 dumper = Dumper(sys.stdout) 211 dump_library(dumper, lib) 212 213def usage(prog): 214 print('Usage: %s <file.gds>' % prog) 215 216if __name__ == '__main__': 217 if (len(sys.argv) > 1): 218 main(sys.argv[1]) 219 else: 220 usage(sys.argv[0]) 221 sys.exit(1) 222 sys.exit(0) 223