class Ronin::Support::Binary::CTypes::StructType

Represents a ‘struct` type.

@api private

@since 1.0.0

Attributes

alignment[R]

The alignment, in bytes, for the struct type, so that all members within the struct type are themselves aligned.

@return [Integer]

members[R]

The members of the struct type.

@return [Hash{Symbol => Member}]

size[R]

The size of the struct type.

@return [Integer, Float::INFINITY]

Public Class Methods

build(fields, alignment: nil, padding: true) click to toggle source

Builds the struct type from the given fields.

@param [Hash{Symbol => Type}] fields

The field names and types for the struct type.

@param [Integer, nil] alignment

Optional custom alignment the struct type.

@param [Boolean] padding

Controls whether to pad struct members for alignment.

@return [StructType]

The new struct type.
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 176
def self.build(fields, alignment: nil, padding: true)
  members       = {}
  max_alignment = 0
  pack_string   = String.new(encoding: Encoding::ASCII_8BIT)

  offset = 0

  fields.each do |name,type|
    pad = if padding then Member.padding_for(offset,type)
          else            0
          end

    members[name] = Member.new(offset + pad,type)
    max_alignment = type.alignment if type.alignment > max_alignment

    if pack_string
      if type.pack_string
        pack_string << Member.pack_string_for(type,pad)
      else
        pack_string = nil
      end
    end

    # omit infinite sizes from the struct size
    unless type.size == Float::INFINITY
      offset += type.size + pad
    end
  end

  return new(members, size:        offset,
                      alignment:   alignment || max_alignment,
                      pack_string: pack_string)
end
new(members, size: , alignment: , pack_string: ) click to toggle source

Initializes the struct type.

@param [Hash{Symbol => Member}] members

The members for the struct type.

@param [Integer, nil] alignment

Optional custom alignment the struct type.

@param [String, nil] pack_string

The String for `Array#pack` or `String#unpack`.
Calls superclass method
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 153
def initialize(members, size: , alignment: , pack_string: )
  @members   = members
  @size      = size
  @alignment = alignment

  super(pack_string: pack_string)
end

Public Instance Methods

align(new_alignment) click to toggle source

Creates a copy of the struct type with a different {#alignment}.

@param [Integer] new_alignment

The new alignment for the new struct type.

@return [ScalarType]

The new struct type.
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 240
def align(new_alignment)
  self.class.new(@members, size:        @size,
                           alignment:   new_alignment,
                           pack_string: pack_string)
end
dequeue_value(values) click to toggle source

Dequeues a Hash from the flat list of values.

@param [Array] values

The flat array of values.

@return [Hash]

The dequeued hash.

@api private

# File lib/ronin/support/binary/ctypes/struct_type.rb, line 345
def dequeue_value(values)
  hash = {}

  @members.each do |name,member|
    hash[name] = member.type.dequeue_value(values)
  end

  return hash
end
enqueue_value(values,hash) click to toggle source

Enqueues a Hash of values onto the flat list of values.

@param [Array] values

The flat array of values.

@param [Hash] hash

The hash to enqueue.

@api private

# File lib/ronin/support/binary/ctypes/struct_type.rb, line 320
def enqueue_value(values,hash)
  unknown_keys = hash.keys - @members.keys

  unless unknown_keys.empty?
    raise(ArgumentError,"unknown struct members: #{unknown_keys.map(&:inspect).join(', ')}")
  end

  @members.each do |name,member|
    value = hash[name] || member.type.uninitialized_value

    member.type.enqueue_value(values,value)
  end
end
length() click to toggle source

The number of members within the struct.

@return [Integer]

# File lib/ronin/support/binary/ctypes/struct_type.rb, line 227
def length
  @members.length
end
pack(hash) click to toggle source

Packs the hash of values into the struct’s binary layout.

@param [Hash{Symbol => Integer, Float, String}] hash

The hash of values to pack.

@return [String]

The packed binary data.
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 255
def pack(hash)
  if @pack_string
    super(hash)
  else
    buffer = String.new("\0" * @size, encoding: Encoding::ASCII_8BIT)

    hash.each do |name,value|
      member = @members.fetch(name) do
        raise(ArgumentError,"unknown struct member (#{name.inspect}), must be: #{@members.keys.map(&:inspect).join(', ')}")
      end

      data = member.type.pack(value)

      if member.size == Float::INFINITY
        buffer[member.offset..] = data
      else
        buffer[member.offset,member.size] = data
      end
    end

    return buffer
  end
end
uninitialized_value() click to toggle source

Creates a new Hash of the struct’s uninitialized members.

@return [Hash{Symbol => Object}]

The uninitialized values for the new struct's members.
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 216
def uninitialized_value
  @members.transform_values do |member|
    member.type.uninitialized_value
  end
end
unpack(data) click to toggle source

Unpacks binary data into a Hash of values using the struct’s binary layout.

@param [String] data

The binary data to unpack.

@return [Hash{Symbol => Integer, Float, String, nil}]

The unpacked hash.
# File lib/ronin/support/binary/ctypes/struct_type.rb, line 289
def unpack(data)
  if @pack_string
    super(data)
  else
    hash = {}

    @members.each do |name,member|
      slice = if member.size == Float::INFINITY
                data.byteslice(member.offset..)
              else
                data.byteslice(member.offset,member.size)
              end

      hash[name] = member.type.unpack(slice)
    end

    return hash
  end
end