Module: Gdsii::Read

Included in:
Group
Defined in:
lib/gdsii/mixins.rb

Overview

This module will be extended into all classes descended of Group (i.e. the high-level GDSII access classes). The extension brings a “read” class method (i.e. singleton) into these classes which enables a GDSII file to be read into these data structures using the BNF specification.

Instance Method Summary collapse

Instance Method Details

#read(file, parent_records = nil, parent_bnf_item = nil, yield_at = nil) {|group| ... } ⇒ Object

Accepts a file handle and reads data from that file handle into an object descended of Group. The parent_records and parent_bnf_item arguments are for internal use only.

Yields:

  • (group)


288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/gdsii/mixins.rb', line 288

def read(file, parent_records=nil, parent_bnf_item=nil, yield_at=nil)
  # Set BNF index at 0, get the BNF items, create an empty grouping object
  i = 0
  bnf_items = bnf_spec.bnf_items
  group = self.new
#      puts "#{self}"
  
  # Loop through the BNF spec for this grouping...
  while i < bnf_items.length do
    bnf_item = bnf_items[i]

    # see what kind of a BNF item this is - a Class or a record type (Fixnum)
    if bnf_item.key.class == Class
      # return if stop_at_class is set to true (used internally for
      # Library#read_header and Cell#read_header).
      yield group if yield_at == :before_group

      # Determine the class to use
      klass = bnf_item.key
      
      # Read from the class
      if bnf_item.multiple?
        if (rec = klass.read(file, group.records, bnf_item))
          # if a record was returned, then add it
          group.records.add(bnf_item.key, rec)
        else
          # if nil was returned, then we're done with the record; next
          i += 1
        end
      else
        # If the record is singular, then get it from the class and
        # increment the counter
        rec = klass.read(file, group.records, bnf_item)
        group.records.set(bnf_item.key, rec)
        i += 1
      end
    else
      # ELSE, a record type is expected (Fixnum)
      rec = Record.read(file)
#          puts "  --> expect #{Gdsii::grt_name(bnf_item.key)}; rec == #{rec.name}"
      if rec.type == bnf_item.key
        # This record matches the grouping BNF item that was expected, so
        # store the data
        if bnf_item.multiple?
          group.records.add(bnf_item.key, rec)
        else
          group.records.set(bnf_item.key, rec)
          i += 1
        end
      else
        # Record does not match expected record as per BNF.  Check that we
        # have data already set in this record or that the record is
        # optional.
        if group.records.has_data?(bnf_item.key) or bnf_item.optional?
          # Already has data - just move to the next record and reset file
          # pointer
          i += 1
          file.seek(-rec.byte_size, IO::SEEK_CUR)
        elsif (parent_bnf_item and parent_bnf_item.key.class == Class and
               (parent_records.has_data?(parent_bnf_item.key) or
                parent_bnf_item.optional?))
          # OK, in this case, we are descended into a Class and did not
          # match the BNF expected.  Furthermore, the parent calling this
          # grouping either already got the data needed or this was an
          # optional class in the first place.  In either case, we're OK
          # and just need to get out - which is what we do by returning
          # nil.
          file.seek(-rec.byte_size, IO::SEEK_CUR)
          return nil
        else
          # Does not match the expected BNF... fail
          raise "Unexpected record while reading GDSII file starting at file position #{file.pos-rec.byte_size}\n" +
            "This record is in the wrong place according to the GDSII specification (from BNF)\n" +
            "Expected record was #{Gdsii::grt_name(bnf_item.key)}; instead, received:\n" +
            "Record type     = #{Gdsii::grt_name(rec.type)}\n" +
            "Data type       = #{Gdsii::gdt_name(rec.data.type)}\n" +
            "Record length   = #{rec.byte_size}\n"
        end
      end
      
    end
  end
  
  # Return this record grouping
  yield group if yield_at == :group
  group
end