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.
Instance Method Summary collapse
- #[](field) ⇒ Object
-
#[]=(field, value) ⇒ Object
End class methods.
Class Method Details
.apply!(string) ⇒ Object
Apply this structure to data in the string, returning an instance of this structure with fields completed
432 433 434 |
# File 'lib/depix/dict.rb', line 432 def apply!(string) consume!(string.unpack(pattern)) end |
.array(name, mapped_to, *extras) {|a.members| ... } ⇒ Object
Define an array of values
384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/depix/dict.rb', line 384 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
406 407 408 409 410 |
# File 'lib/depix/dict.rb', line 406 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
423 424 425 426 427 428 429 |
# File 'lib/depix/dict.rb', line 423 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
343 344 345 |
# File 'lib/depix/dict.rb', line 343 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
461 462 463 |
# File 'lib/depix/dict.rb', line 461 def filler only([]) end |
.inner(name, mapped_to, *extras) ⇒ Object
Define a nested struct
399 400 401 402 403 |
# File 'lib/depix/dict.rb', line 399 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
418 419 420 |
# File 'lib/depix/dict.rb', line 418 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
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/depix/dict.rb', line 438 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
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 498 |
# File 'lib/depix/dict.rb', line 466 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
413 414 415 |
# File 'lib/depix/dict.rb', line 413 def pattern fields.map{|f| f.pattern }.join end |
.r32(name, *extras) ⇒ Object
Define a real number
377 378 379 380 381 |
# File 'lib/depix/dict.rb', line 377 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
362 363 364 365 366 |
# File 'lib/depix/dict.rb', line 362 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
355 356 357 358 359 |
# File 'lib/depix/dict.rb', line 355 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
370 371 372 373 374 |
# File 'lib/depix/dict.rb', line 370 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
348 349 350 351 352 |
# File 'lib/depix/dict.rb', line 348 def validate!(instance) fields.each do | f | f.validate!(instance.send(f.name)) if f.name end end |
Instance Method Details
#[](field) ⇒ Object
513 514 515 |
# File 'lib/depix/dict.rb', line 513 def [](field) send(field) end |
#[]=(field, value) ⇒ Object
End class methods
509 510 511 |
# File 'lib/depix/dict.rb', line 509 def []=(field, value) send("#{field}=", value) end |