Class: Ronin::Support::Binary::Struct
- Extended by:
- CTypes::Mixin
- Defined in:
- lib/ronin/support/binary/struct.rb,
lib/ronin/support/binary/struct/member.rb
Overview
This class provides lazy memory mapped access to an underlying
Generic Binary Struct class.
buffer. This means values are decoded/encoded each time they are read or written to.
Examples
Defining Members
class Point < Ronin::Support::Binary::Struct
member :x, :int32
member :y, :int32
end
Initializing Structs
From a Hash:
point = Point.new(x: 1, y: 2)
From a buffer:
point = Point.new("\x01\x00\x00\x00\xFF\xFF\xFF\xFF")
Reading Fields
point = Point.new("\x01\x00\x00\x00\xFF\xFF\xFF\xFF")
point[:x]
# => 1
point[:y]
# => -1
point.x
# => 1
point.y
# => -1
Packing Structs
class Point < Ronin::Support::Binary::Struct
member :x, :int32
member :y, :int32
end
point = Point.new(x: 10, y: -1)
point.pack
# => "\n\x00\x00\x00\xFF\xFF\xFF\xFF"
Unpacking Structs
class Point < Ronin::Support::Binary::Struct
member :x, :int32
member :y, :int32
end
point = Point.unpack("\x00\x00\x00\x01\xFF\xFF\xFF\xFF")
point.x
# => 1
point.y
# => -1
Inheriting Structs
class Point < Ronin::Support::Binary::Struct
member :x, :int32
member :y, :int32
end
class Point3D < Point
member :z, :int32
end
point = Point.new(x: 100, y: 42)
point3d = Point3D.new(x: 100, y: 42, z: -1)
Array Fields
class MyStruct < Ronin::Support::Binary::Struct
member :x, :uint32
member :nums, [:uint8, 10]
end
struct = MyStruct.new
struct.nums = [0x01, 0x02, 0x03, 0x04]
struct.pack
# => "\x00\x00\x00\x00\x01\x02\x03\x04\x00\x00\x00\x00\x00\x00"
Unbounded Array Fields
class MyStruct < Ronin::Support::Binary::Struct
member :length, :uint32
member :payload, (:uint8..)
end
struct = MyStruct.new
struct.payload = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
struct.pack
# => "\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\a\b"
Struct Endianness
class MyStruct < Ronin::Support::Binary::Struct
platform endian: :big
member :x, :uint32
member :y, :uint32
end
struct = MyStruct.new
struct.x = 0xAABB
struct.y = 0xCCDD
struct.pack
# => "\x00\x00\xAA\xBB\x00\x00\xCC\xDD"
Struct Architecture
class MyStruct < Ronin::Support::Binary::Struct
platform arch: :arm64_be
member :x, :int
member :y, :int
member :f, :double
end
struct = MyStruct.new
struct.x = 100
struct.y = -100
struct.f = (90 / Math::PI)
struct.pack
# => "\x00\x00\x00d\xFF\xFF\xFF\x9C@<\xA5\xDC\x1Ac\xC1\xF8"
Struct Operating System (OS)
class MyStruct < Ronin::Support::Binary::Struct
platform arch: :x86_64, os: :windows
member :x, :long
member :y, :long
end
struct = MyStruct.new
struct.x = 255
struct.y = -1
struct.pack
# => "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF"
Struct Alignment
class Pixel < Ronin::Support::Binary::Struct
align 4
member :r, :uint8
member :g, :uint8
member :b, :uint8
end
class PixelBuf < Ronin::Support::Binary::Struct
member :count, :uint8
member :pixels, [Pixel, 255]
end
pixelbuf = PixelBuf.new
pixelbuf.count = 2
pixelbuf.pixels[0].r = 0xAA
pixelbuf.pixels[0].g = 0xBB
pixelbuf.pixels[0].b = 0xCC
pixelbuf.pixels[1].r = 0xAA
pixelbuf.pixels[1].g = 0xBB
pixelbuf.pixels[1].b = 0xCC
pixelbuf.pack
# => "\x02\x00\x00\x00\xAA\xBB\xCC\xAA\xBB\xCC..."
Disable Struct Padding
class MyStruct < Ronin::Support::Binary::Struct
padding false
member :c, :char
member :i, :int32
end
struct = MyStruct.new
struct.c = 'A'
struct.i = -1
struct.pack
# => "A\xFF\xFF\xFF\xFF"
Defined Under Namespace
Classes: Member
Instance Attribute Summary collapse
-
#type ⇒ CTypes::StructType
readonly
private
The type system used by the struct.
Attributes included from CTypes::Mixin
#arch, #endian, #os, #type_resolver, #type_system
Attributes inherited from Memory
Class Method Summary collapse
-
.align(new_alignment) ⇒ Object
Sets the alignment of the struct.
-
.alignment ⇒ Integer
The alignment of the struct.
-
.has_member?(name) ⇒ Boolean
Determines if the struct has the given member.
-
.member(name, type_signature, **kwargs) ⇒ Object
Defines a member in the struct.
-
.members ⇒ Hash{Symbol => Member}
The members in the struct.
-
.pack(values) ⇒ String
Initializes the struct and then packs it.
-
.padding(new_padding = nil) ⇒ Boolean
Gets or sets whether the struct's members will have padding.
-
.platform(endian: nil, arch: nil, os: nil) ⇒ Hash{Symbol => Object}
Gets or sets the struct's target platform.
-
.read_from(io) ⇒ Struct
Reads the struct from the IO stream.
-
.size ⇒ Integer
The size of the struct.
-
.translate(endian: nil, arch: nil) ⇒ Class<Struct>
Translates the struct class using the given type system into a new struct class.
-
.type ⇒ CTypes::StructObjectType
The type for the struct class.
-
.type_resolver ⇒ CTypes::TypeResolver
The type resolver using Struct.type_system.
-
.type_system ⇒ Types, ...
Gets or sets the struct's type system.
-
.unpack(data) ⇒ Struct
Unpacks data into the struct.
Instance Method Summary collapse
-
#[](name) ⇒ Integer, ...
Reads a value from the struct.
-
#[]=(name, value) ⇒ Integer, ...
Writes a value to the struct.
-
#each {|name, value| ... } ⇒ Enumerator
Enumerates over the members within the struct.
-
#initialize(buffer_or_values = {}) ⇒ Struct
constructor
Initializes the struct.
-
#to_a ⇒ ::Array<Object>
Converts the struct to an Array of values.
-
#to_h ⇒ Hash{Symbol => Object}
Converts the struct to a Hash.
Methods included from CTypes::Mixin
Methods inherited from Memory
#+, #byteslice, #clear, #copy_from, #copy_to, #pack, #read_from, #size
Constructor Details
#initialize(buffer_or_values = {}) ⇒ Struct
Initializes the struct.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/ronin/support/binary/struct.rb', line 288 def initialize(buffer_or_values={}) @type_system = self.class.type_system @type = self.class.type @cache = {} case buffer_or_values when Hash super(@type.size) values = buffer_or_values values.each do |name,value| self[name] = value end when String, ByteSlice buffer = buffer_or_values super(buffer) else raise(ArgumentError,"first argument of #{self.class}.new must be either a Hash of values or a String or #{ByteSlice}") end end |
Instance Attribute Details
#type ⇒ CTypes::StructType (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The type system used by the struct.
252 253 254 |
# File 'lib/ronin/support/binary/struct.rb', line 252 def type @type end |
Class Method Details
.align(new_alignment) ⇒ Object
Sets the alignment of the struct.
705 706 707 |
# File 'lib/ronin/support/binary/struct.rb', line 705 def self.align(new_alignment) @alignment = new_alignment end |
.alignment ⇒ Integer
The alignment of the struct.
691 692 693 694 695 |
# File 'lib/ronin/support/binary/struct.rb', line 691 def self.alignment @alignment ||= if superclass < Struct superclass.alignment end end |
.has_member?(name) ⇒ Boolean
Determines if the struct has the given member.
400 401 402 |
# File 'lib/ronin/support/binary/struct.rb', line 400 def self.has_member?(name) members.has_key?(name.to_sym) end |
.member(name, type_signature, **kwargs) ⇒ Object
Defines a member in the struct.
799 800 801 802 803 804 |
# File 'lib/ronin/support/binary/struct.rb', line 799 def self.member(name,type_signature,**kwargs) self.members[name] = Member.new(name,type_signature,**kwargs) define_method(name) { self[name] } define_method("#{name}=") { |value| self[name] = value } end |
.members ⇒ Hash{Symbol => Member}
The members in the struct.
381 382 383 384 385 386 387 |
# File 'lib/ronin/support/binary/struct.rb', line 381 def self.members @members ||= if superclass < Struct superclass.members.dup else {} end end |
.pack(values) ⇒ String
Initializes the struct and then packs it.
427 428 429 |
# File 'lib/ronin/support/binary/struct.rb', line 427 def self.pack(values) new(values).to_s end |
.padding(new_padding = nil) ⇒ Boolean
Gets or sets whether the struct's members will have padding.
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
# File 'lib/ronin/support/binary/struct.rb', line 720 def self.padding(new_padding=nil) unless new_padding.nil? @padding = new_padding else if @padding.nil? @padding = if superclass < Struct superclass.padding else true end else @padding end end end |
.platform(endian: nil, arch: nil, os: nil) ⇒ Hash{Symbol => Object}
Gets or sets the struct's target platform.
The desired architecture for the struct.
The Operating System (OS) for the struct.
670 671 672 673 674 675 676 677 678 679 680 681 |
# File 'lib/ronin/support/binary/struct.rb', line 670 def self.platform(endian: nil, arch: nil, os: nil) if endian || arch || os @type_system = CTypes.platform(endian: endian, arch: arch, os: os) @platform = {endian: endian, arch: arch, os: os} else @platform ||= if superclass < Struct superclass.platform else {} end end end |
.read_from(io) ⇒ Struct
Reads the struct from the IO stream.
482 483 484 |
# File 'lib/ronin/support/binary/struct.rb', line 482 def self.read_from(io) new.read_from(io) end |
.size ⇒ Integer
The size of the struct.
342 343 344 |
# File 'lib/ronin/support/binary/struct.rb', line 342 def self.size type.size end |
.translate(endian: nil, arch: nil) ⇒ Class<Struct>
Translates the struct class using the given type system into a new struct class.
The new architecture for the struct.
363 364 365 366 367 368 369 370 371 |
# File 'lib/ronin/support/binary/struct.rb', line 363 def self.translate(endian: nil, arch: nil) struct_class = Class.new(self) if arch then struct_class.arch(arch) elsif endian then struct_class.endian(endian) end struct_class end |
.type ⇒ CTypes::StructObjectType
The type for the struct class.
319 320 321 |
# File 'lib/ronin/support/binary/struct.rb', line 319 def self.type @type ||= type_resolver.resolve(self) end |
.type_resolver ⇒ CTypes::TypeResolver
The type resolver using type_system.
760 761 762 |
# File 'lib/ronin/support/binary/struct.rb', line 760 def self.type_resolver @type_resolver ||= CTypes::TypeResolver.new(type_system) end |
.type_system ⇒ Types, ...
Gets or sets the struct's type system.
745 746 747 748 749 750 751 |
# File 'lib/ronin/support/binary/struct.rb', line 745 def self.type_system @type_system ||= if superclass < Struct superclass.type_system else CTypes end end |
.unpack(data) ⇒ Struct
Unpacks data into the struct.
453 454 455 |
# File 'lib/ronin/support/binary/struct.rb', line 453 def self.unpack(data) new(data) end |
Instance Method Details
#[](name) ⇒ Integer, ...
Reads a value from the struct.
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'lib/ronin/support/binary/struct.rb', line 517 def [](name) if (member = @type.members[name]) case member.type when CTypes::UnboundedArrayType # XXX: but how do we handle an unbounded array of structs? @cache[name] ||= begin offset = member.offset length = size - member.offset slice = byteslice(offset,length) Binary::Array.new(member.type.type,slice) end when CTypes::ObjectType @cache[name] ||= begin offset = member.offset length = member.type.size slice = byteslice(offset,length) member.type.unpack(slice) end else data = super(member.offset,member.type.size) member.type.unpack(data) end else raise(ArgumentError,"no such member: #{name.inspect}") end end |
#[]=(name, value) ⇒ Integer, ...
Writes a value to the struct.
583 584 585 586 587 588 589 590 591 592 |
# File 'lib/ronin/support/binary/struct.rb', line 583 def []=(name,value) if (member = @type.members[name]) data = member.type.pack(value) super(member.offset,member.type.size,data) return value else raise(ArgumentError,"no such member: #{name.inspect}") end end |
#each {|name, value| ... } ⇒ Enumerator
Enumerates over the members within the struct.
612 613 614 615 616 617 618 |
# File 'lib/ronin/support/binary/struct.rb', line 612 def each(&block) return enum_for(__method__) unless block_given? @type.members.each_key do |name| yield name, self[name] end end |
#to_a ⇒ ::Array<Object>
Converts the struct to an Array of values.
640 641 642 |
# File 'lib/ronin/support/binary/struct.rb', line 640 def to_a each.map { |name,value| value } end |
#to_h ⇒ Hash{Symbol => Object}
Converts the struct to a Hash.
628 629 630 |
# File 'lib/ronin/support/binary/struct.rb', line 628 def to_h each.to_h end |