Class: Depix::Dict
- Inherits:
-
Object
- Object
- Depix::Dict
- Defined in:
- lib/depix/dict.rb
Overview
Base class for a struct. Could also be implemented as a module actually
Direct Known Subclasses
CompactDPX, DPX, FileInfo, FilmInfo, ImageElement, ImageInfo, OrientationInfo, TelevisionInfo, UserInfo
Constant Summary collapse
- DEF_OPTS =
{ :req => false, :desc => nil }
Class Method Summary collapse
-
.apply!(string) ⇒ Object
Apply this structure to data in the string, returning an instance of this structure with fields completed.
-
.array(name, mapped_to, *extras) {|a.members| ... } ⇒ Object
Define an array of values.
-
.char(name, *extras) ⇒ Object
Define a char field.
-
.consume!(stack_of_unpacked_values) ⇒ Object
Consume a stack of unpacked values, letting each field decide how many to consume.
-
.fields ⇒ Object
Get the array of fields defined in this struct.
-
.filler ⇒ Object
Get an opaque struct based on this one, that will consume exactly as many bytes as this structure would occupy, but discard them instead.
-
.inner(name, mapped_to, *extras) ⇒ Object
Define a nested struct.
-
.length ⇒ Object
How many bytes are needed to complete this structure.
-
.only(*field_names) ⇒ Object
Get a class that would parse just the same, preserving only the fields passed in the array.
-
.pack(instance, buffer = nil) ⇒ Object
Pack the instance of this struct.
-
.pattern ⇒ Object
Get the pattern that will be used to unpack this structure and all of it’s descendants.
-
.r32(name, *extras) ⇒ Object
Define a real number.
-
.u16(name, *extras) ⇒ Object
Define a double-width unsigned integer.
-
.u32(name, *extras) ⇒ Object
Define a 4-byte unsigned integer.
-
.u8(name, *extras) ⇒ Object
Define a small unsigned integer.
-
.validate!(instance) ⇒ Object
Validate a passed instance.
Class Method Details
.apply!(string) ⇒ Object
Apply this structure to data in the string, returning an instance of this structure with fields completed
431 432 433 |
# File 'lib/depix/dict.rb', line 431 def apply!(string) consume!(string.unpack(pattern)) end |
.array(name, mapped_to, *extras) {|a.members| ... } ⇒ Object
Define an array of values
383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/depix/dict.rb', line 383 def array(name, mapped_to, *extras) count, opts = count_and_opts_from(extras) attr_accessor name a = ArrayField.new({:name => name}.merge(opts)) a.members = if mapped_to.is_a?(Class) # Array of structs [InnerField.new(:cast => mapped_to)] * count else [Field.send("emit_#{mapped_to}")] * count end yield a.members if block_given? fields << a end |
.char(name, *extras) ⇒ Object
Define a char field
405 406 407 408 409 |
# File 'lib/depix/dict.rb', line 405 def char(name, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << Field.emit_char( {:name => name, :length => count}.merge(opts) ) end |
.consume!(stack_of_unpacked_values) ⇒ Object
Consume a stack of unpacked values, letting each field decide how many to consume
422 423 424 425 426 427 428 |
# File 'lib/depix/dict.rb', line 422 def consume!(stack_of_unpacked_values) new_item = new @fields.each do | field | new_item.send("#{field.name}=", field.consume!(stack_of_unpacked_values)) unless field.name.nil? end new_item end |
.fields ⇒ Object
Get the array of fields defined in this struct
342 343 344 |
# File 'lib/depix/dict.rb', line 342 def fields @fields ||= [] end |
.filler ⇒ Object
Get an opaque struct based on this one, that will consume exactly as many bytes as this structure would occupy, but discard them instead
460 461 462 |
# File 'lib/depix/dict.rb', line 460 def filler only([]) end |
.inner(name, mapped_to, *extras) ⇒ Object
Define a nested struct
398 399 400 401 402 |
# File 'lib/depix/dict.rb', line 398 def inner(name, mapped_to, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << InnerField.new({:name => name, :cast => mapped_to}.merge(opts)) end |
.length ⇒ Object
How many bytes are needed to complete this structure
417 418 419 |
# File 'lib/depix/dict.rb', line 417 def length fields.inject(0){|_, s| _ + s.length } end |
.only(*field_names) ⇒ Object
Get a class that would parse just the same, preserving only the fields passed in the array. This speeds up parsing because we only extract and conform the fields that we need
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/depix/dict.rb', line 437 def only(*field_names) distillate = fields.inject([]) do | m, f | if field_names.include?(f.name) # preserve m.push(f) else # create filler unless m[-1].is_a?(Filler) m.push(Filler.new(:length => f.length)) else m[-1].length += f.length end m end end anon = Class.new(self) anon.fields.replace(distillate) only_items = distillate.map{|n| n.name } anon end |
.pack(instance, buffer = nil) ⇒ Object
Pack the instance of this struct
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
# File 'lib/depix/dict.rb', line 465 def pack(instance, buffer = nil) # Preallocate a buffer just as big as me since we want everything to remain at fixed offsets buffer ||= ("\000" * length) # If the instance is nil return pure padding return buffer if instance.nil? # Now for the important stuff. For each field that we have, replace a piece at offsets in the buffer # with the packed results, skipping fillers fields.each_with_index do | f, i | # Skip blanking, we just dont touch it. TODO - test! next if f.is_a?(Filler) # Where should we put that value? offset = fields[0...i].inject(0){|_, s| _ + s.length } val = instance.send(f.name) # Validate the passed value using the format the field supports f.validate!(val) packed = f.pack(val) # Signal offset violation raise "Improper length for #{f.name} - packed #{packed.length} bytes but #{f.length} is required to fill the slot" if packed.length != f.length buffer[offset...(offset+f.length)] = packed end raise "Resulting buffer not the same length, expected #{length} bytes but compued #{buffer.length}" if buffer.length != length buffer end |
.pattern ⇒ Object
Get the pattern that will be used to unpack this structure and all of it’s descendants
412 413 414 |
# File 'lib/depix/dict.rb', line 412 def pattern fields.map{|f| f.pattern }.join end |
.r32(name, *extras) ⇒ Object
Define a real number
376 377 378 379 380 |
# File 'lib/depix/dict.rb', line 376 def r32(name, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << Field.emit_r32( {:name => name}.merge(opts) ) end |
.u16(name, *extras) ⇒ Object
Define a double-width unsigned integer
361 362 363 364 365 |
# File 'lib/depix/dict.rb', line 361 def u16(name, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << Field.emit_u16( {:name => name }.merge(opts) ) end |
.u32(name, *extras) ⇒ Object
Define a 4-byte unsigned integer
354 355 356 357 358 |
# File 'lib/depix/dict.rb', line 354 def u32(name, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << Field.emit_u32( {:name => name }.merge(opts) ) end |
.u8(name, *extras) ⇒ Object
Define a small unsigned integer
369 370 371 372 373 |
# File 'lib/depix/dict.rb', line 369 def u8(name, *extras) count, opts = count_and_opts_from(extras) attr_accessor name fields << Field.emit_u8( {:name => name }.merge(opts) ) end |
.validate!(instance) ⇒ Object
Validate a passed instance
347 348 349 350 351 |
# File 'lib/depix/dict.rb', line 347 def validate!(instance) fields.each do | f | f.validate!(instance.send(f.name)) if f.name end end |