jfreeze-ruby-gdsii 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +6 -0
- data/LICENSE.txt +20 -0
- data/README.txt +113 -0
- data/Rakefile +30 -0
- data/bin/rgds-debug +43 -0
- data/bin/rgds-dump +38 -0
- data/bin/rgds-join +98 -0
- data/bin/rgds-layers +53 -0
- data/bin/rgds-sremove +136 -0
- data/bin/rgds-ssplit +113 -0
- data/bin/rgds-stats +134 -0
- data/bin/rgds-structs +41 -0
- data/bin/rgds-tree +167 -0
- data/bin/rgds2rb +99 -0
- data/lib/gdsii.rb +137 -0
- data/lib/gdsii/aref.rb +243 -0
- data/lib/gdsii/bnf.rb +309 -0
- data/lib/gdsii/boundary.rb +53 -0
- data/lib/gdsii/box.rb +65 -0
- data/lib/gdsii/byte_order.rb +36 -0
- data/lib/gdsii/element.rb +172 -0
- data/lib/gdsii/group.rb +98 -0
- data/lib/gdsii/library.rb +518 -0
- data/lib/gdsii/mixins.rb +378 -0
- data/lib/gdsii/node.rb +65 -0
- data/lib/gdsii/path.rb +169 -0
- data/lib/gdsii/property.rb +108 -0
- data/lib/gdsii/record.rb +606 -0
- data/lib/gdsii/record/consts.rb +384 -0
- data/lib/gdsii/record/datatypes/ascii.rb +145 -0
- data/lib/gdsii/record/datatypes/bitarray.rb +101 -0
- data/lib/gdsii/record/datatypes/data.rb +111 -0
- data/lib/gdsii/record/datatypes/int2.rb +67 -0
- data/lib/gdsii/record/datatypes/int4.rb +65 -0
- data/lib/gdsii/record/datatypes/nodata.rb +60 -0
- data/lib/gdsii/record/datatypes/real4.rb +51 -0
- data/lib/gdsii/record/datatypes/real8.rb +120 -0
- data/lib/gdsii/sref.rb +61 -0
- data/lib/gdsii/strans.rb +133 -0
- data/lib/gdsii/structure.rb +352 -0
- data/lib/gdsii/text.rb +203 -0
- data/pkg/ruby-gdsii.gem +46 -0
- data/samples/hello.gds +0 -0
- data/samples/hello.out.rb +84 -0
- data/samples/hello.rb +94 -0
- data/test/baseline/dcp1.gds +0 -0
- data/test/baseline/h_write.gds +0 -0
- data/test/h_pthru.rb +22 -0
- data/test/h_write.rb +117 -0
- data/test/hs_pthru.rb +31 -0
- data/test/l_pthru.rb +23 -0
- data/test/test_gds_group.rb +379 -0
- data/test/test_gds_record.rb +99 -0
- metadata +117 -0
@@ -0,0 +1,384 @@
|
|
1
|
+
module Gdsii
|
2
|
+
|
3
|
+
#
|
4
|
+
# Class to store information about each record type. The Gdsii::RECORD_INFO
|
5
|
+
# constant is an array with an index of the record type number and the value
|
6
|
+
# being instances of this class. For example:
|
7
|
+
#
|
8
|
+
# Gdsii::RECORD_INFO[Gdsii::GRT_HEADER].name #=> 'HEADER'
|
9
|
+
# Gdsii::RECORD_INFO[Gdsii::GRT_XY].min_len #=> 4
|
10
|
+
#
|
11
|
+
# See the Gdsii module for a complete listing of record type constants
|
12
|
+
# (Gdsii::GRT_*).
|
13
|
+
#
|
14
|
+
class RecInfo
|
15
|
+
|
16
|
+
# Name of this record (should be the same as the Gdsii::GRT_* name but
|
17
|
+
# without the "Gdsii::GRT_".
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# Record type is an integer of the constant Gdsii::GRT_* for this record
|
21
|
+
# type.
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# Boolean as to whether or not this record is a valid GDS record (some
|
25
|
+
# records are not valid to the GDS specification)
|
26
|
+
attr_reader :valid
|
27
|
+
|
28
|
+
# Data type is an integer of the constant Gdsii::GDT_* for this record.
|
29
|
+
# This represents the data type expected for this record.
|
30
|
+
attr_reader :data_type
|
31
|
+
|
32
|
+
# Size indicates how many bytes are necessary to store each element of
|
33
|
+
# this record. For example, the size of a Gdsii::GRT_XY record is 8 with a
|
34
|
+
# record size of 4 bytes for each record (since it's a Gdsii::GDT_INT4).
|
35
|
+
# This means that the minimum number of items needed (#min_items) is 2.
|
36
|
+
attr_reader :size
|
37
|
+
|
38
|
+
# Minimum length (in bytes) to store this record
|
39
|
+
attr_reader :min_len
|
40
|
+
|
41
|
+
# Maximum length (in bytes) to store this record
|
42
|
+
attr_reader :max_len
|
43
|
+
|
44
|
+
# Object constructor. Intended to be used internally only to add elements
|
45
|
+
# to the Gdsii::RECORD_INFO array.
|
46
|
+
def initialize(name, data_type, valid, size, min_len, max_len)
|
47
|
+
@name = name
|
48
|
+
@data_type = data_type
|
49
|
+
@valid = valid
|
50
|
+
@size = size
|
51
|
+
@min_len = min_len
|
52
|
+
@max_len = max_len
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns the minimum number of items necessary for this record type.
|
56
|
+
def min_items
|
57
|
+
case @data_type
|
58
|
+
when GDT_NO_DATA : 0
|
59
|
+
when GDT_ASCII : (@size == 0) ? 1 : @min_len/@size
|
60
|
+
else
|
61
|
+
@min_len/@size
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns the maximum number of items necessary for this record type.
|
66
|
+
def max_items
|
67
|
+
case @data_type
|
68
|
+
when GDT_NO_DATA : 0
|
69
|
+
when GDT_ASCII : (@size == 0) ? 1 : @max_len/@size
|
70
|
+
else
|
71
|
+
@max_len/@size
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns true if this object has only a single datum; false if it can
|
76
|
+
# have multiple data.
|
77
|
+
def single_data_value?
|
78
|
+
if @data_type == GDT_ASCII
|
79
|
+
@size == 0
|
80
|
+
else
|
81
|
+
@size == @min_len and @size == @max_len
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Converts this record to a string (returns the record's name)
|
86
|
+
def to_s(); @name; end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
############################################################################
|
91
|
+
|
92
|
+
#
|
93
|
+
# Class to store information about each record data type. The
|
94
|
+
# Gdsii::DATATYPE_INFO array has an index of GDT_* integer values with the
|
95
|
+
# value being an instance of this class. For example:
|
96
|
+
#
|
97
|
+
# Gdsii::RECORD_INFO[Gdsii::GDT_ASCII].name #=> 'ASCII'
|
98
|
+
# Gdsii::RECORD_INFO[Gdsii::GDT_REAL4].valid #=> false
|
99
|
+
#
|
100
|
+
class RecDataTypeInfo
|
101
|
+
|
102
|
+
# Name of this record data type (should be the same as the Gdsii::GDT_* name
|
103
|
+
# but without the "Gdsii::GDT_".
|
104
|
+
attr_reader :name
|
105
|
+
|
106
|
+
# Boolean value indicating whether or not this record data type is valid.
|
107
|
+
attr_reader :valid
|
108
|
+
|
109
|
+
# Integer value indicating the size (in bytes) required for this data
|
110
|
+
# type. The exception is Gdsii::GDT_ASCII which has a size of 0 but in
|
111
|
+
# actuality has a variable-length size.
|
112
|
+
attr_reader :size
|
113
|
+
|
114
|
+
# Object constructor. Intended to be used internally only to add elements
|
115
|
+
# to the Gdsii::DATATYPE_INFO array.
|
116
|
+
def initialize(name, valid, size)
|
117
|
+
@name = name
|
118
|
+
@valid = valid
|
119
|
+
@size = size
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the data type's name
|
123
|
+
def to_s(); @name; end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
############################################################################
|
128
|
+
|
129
|
+
# These numbers correspond to GDSII format indicating the path types
|
130
|
+
if not defined?(PATHTYPE_FLUSH)
|
131
|
+
PATHTYPE_FLUSH = 0
|
132
|
+
PATHTYPE_ROUND = 1
|
133
|
+
PATHTYPE_EXTEND = 2
|
134
|
+
PATHTYPE_CUSTOM = 4
|
135
|
+
|
136
|
+
# These numbers correspond to GDSII format
|
137
|
+
FORMAT_GDSII_ARCHIVE = 0
|
138
|
+
FORMAT_GDSII_FILTERED = 1
|
139
|
+
FORMAT_EDSIII_ARCHIVE = 2
|
140
|
+
FORMAT_EDSIII_FILTERED = 3
|
141
|
+
|
142
|
+
# These are GDSII record numbers and correspond to the GDSII number in the
|
143
|
+
# GDSII file specification
|
144
|
+
GRT_HEADER = 0
|
145
|
+
GRT_BGNLIB = 1
|
146
|
+
GRT_LIBNAME = 2
|
147
|
+
GRT_UNITS = 3
|
148
|
+
GRT_ENDLIB = 4
|
149
|
+
GRT_BGNSTR = 5
|
150
|
+
GRT_STRNAME = 6
|
151
|
+
GRT_ENDSTR = 7
|
152
|
+
GRT_BOUNDARY = 8
|
153
|
+
GRT_PATH = 9
|
154
|
+
GRT_SREF = 10
|
155
|
+
|
156
|
+
GRT_AREF = 11
|
157
|
+
GRT_TEXT = 12
|
158
|
+
GRT_LAYER = 13
|
159
|
+
GRT_DATATYPE = 14
|
160
|
+
GRT_WIDTH = 15
|
161
|
+
GRT_XY = 16
|
162
|
+
GRT_ENDEL = 17
|
163
|
+
GRT_SNAME = 18
|
164
|
+
GRT_COLROW = 19
|
165
|
+
GRT_TEXTNODE = 20
|
166
|
+
|
167
|
+
GRT_NODE = 21
|
168
|
+
GRT_TEXTTYPE = 22
|
169
|
+
GRT_PRESENTATION = 23
|
170
|
+
GRT_SPACING = 24
|
171
|
+
GRT_STRING = 25
|
172
|
+
GRT_STRANS = 26
|
173
|
+
GRT_MAG = 27
|
174
|
+
GRT_ANGLE = 28
|
175
|
+
GRT_UINTEGER = 29
|
176
|
+
GRT_USTRING = 30
|
177
|
+
|
178
|
+
GRT_REFLIBS = 31
|
179
|
+
GRT_FONTS = 32
|
180
|
+
GRT_PATHTYPE = 33
|
181
|
+
GRT_GENERATIONS = 34
|
182
|
+
GRT_ATTRTABLE = 35
|
183
|
+
GRT_STYPTABLE = 36
|
184
|
+
GRT_STRTYPE = 37
|
185
|
+
GRT_ELFLAGS = 38
|
186
|
+
GRT_ELKEY = 39
|
187
|
+
GRT_LINKTYPE = 40
|
188
|
+
|
189
|
+
GRT_LINKKEYS = 41
|
190
|
+
GRT_NODETYPE = 42
|
191
|
+
GRT_PROPATTR = 43
|
192
|
+
GRT_PROPVALUE = 44
|
193
|
+
GRT_BOX = 45
|
194
|
+
GRT_BOXTYPE = 46
|
195
|
+
GRT_PLEX = 47
|
196
|
+
GRT_BGNEXTN = 48
|
197
|
+
GRT_ENDEXTN = 49
|
198
|
+
GRT_TAPENUM = 50
|
199
|
+
|
200
|
+
GRT_TAPECODE = 51
|
201
|
+
GRT_STRCLASS = 52
|
202
|
+
GRT_RESERVED = 53
|
203
|
+
GRT_FORMAT = 54
|
204
|
+
GRT_MASK = 55
|
205
|
+
GRT_ENDMASKS = 56
|
206
|
+
GRT_LIBDIRSIZE = 57
|
207
|
+
GRT_SRFNAME = 58
|
208
|
+
GRT_LIBSECUR = 59
|
209
|
+
GRT_BORDER = 60
|
210
|
+
|
211
|
+
GRT_SOFTFENCE = 61
|
212
|
+
GRT_HARDFENCE = 62
|
213
|
+
GRT_SOFTWIRE = 63
|
214
|
+
GRT_HARDWIRE = 64
|
215
|
+
GRT_PATHPORT = 65
|
216
|
+
GRT_NODEPORT = 66
|
217
|
+
GRT_USERCONSTRAINT = 67
|
218
|
+
GRT_SPACER_ERROR = 68
|
219
|
+
GRT_CONTACT = 69
|
220
|
+
|
221
|
+
# GDSII record data types
|
222
|
+
GDT_NO_DATA = 0
|
223
|
+
GDT_BITARRAY = 1
|
224
|
+
GDT_INT2 = 2
|
225
|
+
GDT_INT4 = 3
|
226
|
+
GDT_REAL4 = 4
|
227
|
+
GDT_REAL8 = 5
|
228
|
+
GDT_ASCII = 6
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
if not defined?(RECORD_INFO)
|
233
|
+
|
234
|
+
# Gdsii::RECORD_INFO is an array of Gdsii::RecInfo objects. The array order
|
235
|
+
# is significant in that the index of the array is the value of the record
|
236
|
+
# and corresponds to the Gdsii::GRT_* constant values. This allows easy
|
237
|
+
# validation lookup based upon the record type constants. Example:
|
238
|
+
#
|
239
|
+
# Gdsii::RECORD_INFO[Gdsii::GRT_HEADER].name # => "HEADER"
|
240
|
+
# Gdsii::RECORD_INFO[Gdsii::GRT_HEADER].valid # => true
|
241
|
+
# Gdsii::RECORD_INFO[Gdsii::GRT_HEADER].data_type # => 2
|
242
|
+
#
|
243
|
+
RECORD_INFO =
|
244
|
+
[
|
245
|
+
# name data_type valid size minlen maxlen num
|
246
|
+
RecInfo.new('HEADER', GDT_INT2, true, 2, 2, 2), # 0 - GDS version
|
247
|
+
RecInfo.new('BGNLIB', GDT_INT2, true, 2, 24, 24), # 1 - Modification & access time
|
248
|
+
RecInfo.new('LIBNAME', GDT_ASCII, true, 0, 0, 65530), # 2
|
249
|
+
RecInfo.new('UNITS', GDT_REAL8, true, 8, 16, 16), # 3
|
250
|
+
RecInfo.new('ENDLIB', GDT_NO_DATA, true, 0, 0, 0), # 4
|
251
|
+
RecInfo.new('BGNSTR', GDT_INT2, true, 2, 24, 24), # 5
|
252
|
+
|
253
|
+
RecInfo.new('STRNAME', GDT_ASCII, true, 0, 2, 512), # 6
|
254
|
+
RecInfo.new('ENDSTR', GDT_NO_DATA, true, 0, 0, 0), # 7
|
255
|
+
RecInfo.new('BOUNDARY', GDT_NO_DATA, true, 0, 0, 0), # 8
|
256
|
+
RecInfo.new('PATH', GDT_NO_DATA, true, 0, 0, 0), # 9
|
257
|
+
RecInfo.new('SREF', GDT_NO_DATA, true, 0, 0, 0), # 10
|
258
|
+
|
259
|
+
RecInfo.new('AREF', GDT_NO_DATA, true, 0, 0, 0), # 11
|
260
|
+
RecInfo.new('TEXT', GDT_NO_DATA, true, 0, 0, 0), # 12
|
261
|
+
RecInfo.new('LAYER', GDT_INT2, true, 2, 2, 2), # 13
|
262
|
+
RecInfo.new('DATATYPE', GDT_INT2, true, 2, 2, 2), # 14
|
263
|
+
RecInfo.new('WIDTH', GDT_INT4, true, 4, 4, 4), # 15
|
264
|
+
|
265
|
+
RecInfo.new('XY', GDT_INT4, true, 4, 8, 65528), # 16
|
266
|
+
RecInfo.new('ENDEL', GDT_NO_DATA, true, 0, 0, 0), # 17
|
267
|
+
RecInfo.new('SNAME', GDT_ASCII, true, 0, 2, 65530), # 18
|
268
|
+
RecInfo.new('COLROW', GDT_INT2, true, 2, 4, 4), # 19
|
269
|
+
RecInfo.new('TEXTNODE', GDT_NO_DATA, true, 0, 0, 0), # 20
|
270
|
+
|
271
|
+
RecInfo.new('NODE', GDT_NO_DATA, true, 0, 0, 0), # 21
|
272
|
+
RecInfo.new('TEXTTYPE', GDT_INT2, true, 2, 2, 2), # 22
|
273
|
+
RecInfo.new('PRESENTATION', GDT_BITARRAY, true, 2, 2, 2), # 23
|
274
|
+
RecInfo.new('SPACING', 0, false, 0, 0, 0), # 24
|
275
|
+
RecInfo.new('STRING', GDT_ASCII, true, 0, 2, 512), # 25
|
276
|
+
|
277
|
+
RecInfo.new('STRANS', GDT_BITARRAY, true, 2, 2, 2), # 26
|
278
|
+
RecInfo.new('MAG', GDT_REAL8, true, 8, 8, 8), # 27
|
279
|
+
RecInfo.new('ANGLE', GDT_REAL8, true, 8, 8, 8), # 28
|
280
|
+
RecInfo.new('UINTEGER', 0, false, 0, 0, 0), # 29
|
281
|
+
RecInfo.new('USTRING', 0, false, 0, 0, 0), # 30
|
282
|
+
|
283
|
+
RecInfo.new('REFLIBS', GDT_ASCII, true, 44, 88, 748), # 31
|
284
|
+
RecInfo.new('FONTS', GDT_ASCII, true, 44, 176, 176), # 32 - paths to text font def files
|
285
|
+
RecInfo.new('PATHTYPE', GDT_INT2, true, 2, 2, 2), # 33
|
286
|
+
RecInfo.new('GENERATIONS', GDT_INT2, true, 2, 2, 2), # 34
|
287
|
+
RecInfo.new('ATTRTABLE', GDT_ASCII, true, 0, 2, 44), # 35 - path of attr def file
|
288
|
+
|
289
|
+
RecInfo.new('STYPTABLE', 0, false, 0, 0, 0), # 36
|
290
|
+
RecInfo.new('STRTYPE', 0, false, 0, 0, 0), # 37
|
291
|
+
RecInfo.new('ELFLAGS', GDT_BITARRAY, true, 2, 2, 2), # 38
|
292
|
+
RecInfo.new('ELKEY', 0, false, 0, 0, 0), # 39
|
293
|
+
RecInfo.new('LINKTYPE', 0, false, 0, 0, 0), # 40
|
294
|
+
|
295
|
+
RecInfo.new('LINKKEYS', 0, false, 0, 0, 0), # 41
|
296
|
+
RecInfo.new('NODETYPE', GDT_INT2, true, 2, 2, 2), # 42
|
297
|
+
RecInfo.new('PROPATTR', GDT_INT2, true, 2, 2, 2), # 43
|
298
|
+
RecInfo.new('PROPVALUE', GDT_ASCII, true, 0, 2, 126), # 44
|
299
|
+
RecInfo.new('BOX', GDT_NO_DATA, true, 0, 0, 0), # 45
|
300
|
+
|
301
|
+
RecInfo.new('BOXTYPE', GDT_INT2, true, 2, 2, 2), # 46
|
302
|
+
RecInfo.new('PLEX', GDT_INT4, true, 4, 4, 4), # 47
|
303
|
+
RecInfo.new('BGNEXTN', GDT_INT4, true, 4, 4, 4), # 48
|
304
|
+
RecInfo.new('ENDEXTN', GDT_INT4, true, 4, 4, 4), # 49
|
305
|
+
RecInfo.new('TAPENUM', GDT_INT2, true, 2, 2, 2), # 50
|
306
|
+
|
307
|
+
RecInfo.new('TAPECODE', GDT_INT2, true, 2, 12, 12), # 51
|
308
|
+
RecInfo.new('STRCLASS', GDT_BITARRAY, true, 2, 2, 2), # 52
|
309
|
+
RecInfo.new('RESERVED', 0, false, 0, 0, 0), # 53
|
310
|
+
RecInfo.new('FORMAT', GDT_INT2, true, 2, 2, 2), # 54 - GdsiiFormat type
|
311
|
+
RecInfo.new('MASK', GDT_ASCII, true, 0, 2, 65530), # 55
|
312
|
+
|
313
|
+
RecInfo.new('ENDMASKS', GDT_NO_DATA, true, 0, 0, 0), # 56
|
314
|
+
RecInfo.new('LIBDIRSIZE', GDT_INT2, true, 2, 2, 2), # 57 - # of pages in lib dir
|
315
|
+
RecInfo.new('SRFNAME', GDT_ASCII, true, 0, 2, 65530), # 58 - name of spacing rules file
|
316
|
+
RecInfo.new('LIBSECUR', GDT_INT2, true, 2, 6, 192), # 59 - array of ACL data
|
317
|
+
RecInfo.new('BORDER', GDT_NO_DATA, true, 0, 0, 0), # 60
|
318
|
+
|
319
|
+
RecInfo.new('SOFTFENCE', GDT_NO_DATA, true, 0, 0, 0), # 61
|
320
|
+
RecInfo.new('HARDFENCE', GDT_NO_DATA, true, 0, 0, 0), # 62
|
321
|
+
RecInfo.new('SOFTWIRE', GDT_NO_DATA, true, 0, 0, 0), # 63
|
322
|
+
RecInfo.new('HARDWIRE', GDT_NO_DATA, true, 0, 0, 0), # 64
|
323
|
+
RecInfo.new('PATHPORT', GDT_NO_DATA, true, 0, 0, 0), # 65
|
324
|
+
|
325
|
+
RecInfo.new('NODEPORT', GDT_NO_DATA, true, 0, 0, 0), # 66
|
326
|
+
RecInfo.new('USERCONSTRAINT', GDT_NO_DATA, true, 0, 0, 0), # 67
|
327
|
+
RecInfo.new('SPACER_ERROR', GDT_NO_DATA, true, 0, 0, 0), # 68
|
328
|
+
RecInfo.new('CONTACT', GDT_NO_DATA, true, 0, 0, 0), # 69
|
329
|
+
]
|
330
|
+
|
331
|
+
#
|
332
|
+
# Gdsii::DATATYPE_INFO is an array of Gdsii::RecDataTypeInfo objects. The array
|
333
|
+
# order is significant in that the index of the array is the value of the
|
334
|
+
# record data type constant. This allows easy validation lookup based upon
|
335
|
+
# the record data type constants. Example:
|
336
|
+
#
|
337
|
+
# Gdsii::DATATYPE_INFO[Gdsii::GRT_REAL8].name # => "REAL8"
|
338
|
+
# Gdsii::DATATYPE_INFO[Gdsii::GRT_REAL8].valid # => true
|
339
|
+
# Gdsii::DATATYPE_INFO[Gdsii::GRT_REAL8].size # => 8
|
340
|
+
#
|
341
|
+
DATATYPE_INFO =
|
342
|
+
[
|
343
|
+
RecDataTypeInfo.new('NO_DATA', true, 0 ), # 0
|
344
|
+
RecDataTypeInfo.new('BITARRAY', true, 2 ), # 1
|
345
|
+
RecDataTypeInfo.new('INT2', true, 2 ), # 2
|
346
|
+
RecDataTypeInfo.new('INT4', true, 4 ), # 3
|
347
|
+
RecDataTypeInfo.new('REAL4', false, 4 ), # 4
|
348
|
+
RecDataTypeInfo.new('REAL8', true, 8 ), # 5
|
349
|
+
RecDataTypeInfo.new('ASCII', true, 0 ), # 6 ; string len is variable
|
350
|
+
]
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns the name for given record type if it is found; if not, then
|
354
|
+
# the record number formatted as a String is returned
|
355
|
+
def grt_name(grt_number)
|
356
|
+
if grt_number.class == Fixnum
|
357
|
+
if (0..RECORD_INFO.length-1).member?(grt_number)
|
358
|
+
RECORD_INFO[grt_number].name
|
359
|
+
else
|
360
|
+
grt_number.to_s
|
361
|
+
end
|
362
|
+
else
|
363
|
+
grt_number.inspect
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# Returns the name for given record data type if it is found; if not, then
|
368
|
+
# the record data type number formatted as a String is returned
|
369
|
+
def gdt_name(gdt_number)
|
370
|
+
if gdt_number.class == Fixnum
|
371
|
+
if (0..DATATYPE_INFO.length-1).member?(gdt_number)
|
372
|
+
DATATYPE_INFO[gdt_number].name
|
373
|
+
else
|
374
|
+
gdt_number.to_s
|
375
|
+
end
|
376
|
+
else
|
377
|
+
gdt_number.inspect
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
module_function :grt_name
|
382
|
+
module_function :gdt_name
|
383
|
+
|
384
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'gdsii/record/datatypes/data'
|
2
|
+
|
3
|
+
module Gdsii
|
4
|
+
|
5
|
+
module RecData
|
6
|
+
|
7
|
+
#
|
8
|
+
# Class for ASCII data type
|
9
|
+
#
|
10
|
+
class Ascii < Data
|
11
|
+
|
12
|
+
# Value is an array of strings. Most Gdsii::RecData::Ascii records only
|
13
|
+
# have a single value.
|
14
|
+
attr_reader :value
|
15
|
+
|
16
|
+
# Construct an Gdsii::RecData::Ascii data object. The value is an array
|
17
|
+
# of strings (String).
|
18
|
+
def initialize(value, record=nil)
|
19
|
+
super(GDT_ASCII, value, record)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set the value for this object; verify that the value items are of
|
23
|
+
# type String (or at least can be coerced using "to_s").
|
24
|
+
def value=(value)
|
25
|
+
@value = Data.coerce_value(value, String, :to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the size of the record *data* in bytes. This will *always*
|
29
|
+
# return an even-length (multiple of 2) number since odd-length GDSII
|
30
|
+
# strings are padded with null characters when written to a file. If the
|
31
|
+
# record type has a specific size (i.e. Gdsii::GRT_FONTS and
|
32
|
+
# Gdsii::GRT_REFLIBS) then that size will automatically be used for each
|
33
|
+
# element in the value array.
|
34
|
+
def byte_size()
|
35
|
+
if @record and RECORD_INFO[@record.type].size > 0 then
|
36
|
+
RECORD_INFO[@record.type].size * @value.length
|
37
|
+
else
|
38
|
+
sum = 0
|
39
|
+
@value.each do |val|
|
40
|
+
sum += (val.length % 2 == 0) ? val.length : val.length + 1
|
41
|
+
end
|
42
|
+
sum
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return value with stripped off trailing null characters (which are
|
47
|
+
# present when reading this record from a file). For example, assuming
|
48
|
+
# that a record is read from a file and is a null padded string
|
49
|
+
# "hello\0", then:
|
50
|
+
#
|
51
|
+
# record.inspect #=> ["hello\0"]
|
52
|
+
# record.unpad.inspect #=> ["hello"]
|
53
|
+
#
|
54
|
+
def unpad()
|
55
|
+
new_arr = []
|
56
|
+
@value.each do |string|
|
57
|
+
string = string.dup # to avoid changing the original
|
58
|
+
while (string[-1] == 0)
|
59
|
+
string.chop!
|
60
|
+
end
|
61
|
+
new_arr.push string
|
62
|
+
end
|
63
|
+
new_arr
|
64
|
+
end
|
65
|
+
|
66
|
+
# Same as #unpad but modifies the value of this object.
|
67
|
+
def unpad!()
|
68
|
+
@value = unpad
|
69
|
+
end
|
70
|
+
|
71
|
+
# Pad the value with a null character if the string is odd (but do not
|
72
|
+
# change the value itself). If a desired string length is given, then
|
73
|
+
# the string will be padded by the length given. For example, if we
|
74
|
+
# created a record with the string "hello", then padding will add a
|
75
|
+
# null character since "hello" has an odd number of characters:
|
76
|
+
#
|
77
|
+
# record = Gdsii::RecType::Ascii.new(["hello"])
|
78
|
+
# record.pad.inspect #=> ["hello\0"]
|
79
|
+
#
|
80
|
+
def pad(str_length=nil)
|
81
|
+
new_arr = []
|
82
|
+
@value.each_with_index do |string, i|
|
83
|
+
string = string.dup # to avoid changing the original
|
84
|
+
if str_length.nil? then
|
85
|
+
# pad if the string is odd or use the size property if there is a
|
86
|
+
# predefined size
|
87
|
+
if @record and (size=RECORD_INFO[@record.type].size) > 0 then
|
88
|
+
new_arr.push [string].pack("a#{size}")
|
89
|
+
elsif (len=string.length)%2 == 1 then
|
90
|
+
new_arr.push [string].pack("a#{len+1}")
|
91
|
+
else
|
92
|
+
new_arr.push string
|
93
|
+
end
|
94
|
+
else
|
95
|
+
# A desired string length was given; ensure that the requested
|
96
|
+
# length is a multiple of 2 and is not less than the string given.
|
97
|
+
if str_length%2 == 1 then
|
98
|
+
raise ArgumentError,
|
99
|
+
"Desired string length must be a multiple of 2"
|
100
|
+
elsif str_length < string.length then
|
101
|
+
raise ArgumentError,
|
102
|
+
"Desired string length given #{str_length} is less than actual string length #{string.length}"
|
103
|
+
else
|
104
|
+
new_arr.push [string].pack("a#{str_length}")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
new_arr
|
109
|
+
end
|
110
|
+
|
111
|
+
# Same as #pad except the value of this object is modified.
|
112
|
+
def pad!(str_length=nil)
|
113
|
+
@value = pad(str_length)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Reads an ASCII record from the given file for the length of bytes
|
117
|
+
# given and returns a new Gdsii::RecData::Ascii object.
|
118
|
+
def Ascii.read(file, byte_count)
|
119
|
+
# Verify byte count is even
|
120
|
+
if byte_count%2 == 1 then
|
121
|
+
raise ArgumentError,
|
122
|
+
"GDT_ASCII records must have an even length; requested: #{byte_count}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# read the string in; unpad; and return the new Gdsii::Ascii object
|
126
|
+
raw = file.read(byte_count)
|
127
|
+
string = raw.unpack("a#{byte_count}")
|
128
|
+
data = Ascii.new(string)
|
129
|
+
data.unpad!
|
130
|
+
end
|
131
|
+
|
132
|
+
# Writes the string values in this Gdsii::RecData::Ascii object to the
|
133
|
+
# given file as a GDSII ASCII record.
|
134
|
+
def write(file)
|
135
|
+
padded_str = self.pad
|
136
|
+
file.write padded_str
|
137
|
+
end
|
138
|
+
|
139
|
+
# Joins all strings in the array with spaces and returns the joined
|
140
|
+
# string.
|
141
|
+
def to_s(); self.unpad[0] end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|