class Ronin::Support::Binary::Template

Provides a translation layer between C-types and Ruby ‘Array#pack` codes.

## Supported Types

@see rubydoc.info/stdlib/core/Array:pack

@api pbulic

Attributes

fields[R]

The fields of the binary template.

@return [::Array<Symbol, (Symbol, Integer), Range(Symbol)>]

pack_string[R]

The ‘Array#pack` string for the binary template.

@return [String]

@since 1.0.0

types[R]

The field types of the binary template.

@return [::Array<CTypes::Type,

CTypes::ArrayType,
CTypes::UnboundArrayType>]

@since 1.0.0

Public Class Methods

[](*fields,**kwargs) click to toggle source

Alias for ‘Template.new`.

@param [::Array<Symbol, (Symbol, Integer)>] fields

The C-types which the packer will use.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments.

@option kwargs [:little, :big, :net, nil] :endian

The desired endianness of the values within the template.

@option kwargs [:x86, :x86_64,

              :ppc, :ppc64,
              :mips, :mips_le, :mips_be,
              :mips64, :mips64_le, :mips64_be,
              :arm, :arm_le, :arm_be,
              :arm64, :arm64_le, :arm64_be] :arch
The desired architecture for the values within the template.

@option kwargs [:linux, :macos, :windows,

              :android, :apple_ios, :bsd,
              :freebsd, :openbsd, :netbsd] :os
The Operating System (OS) to use.

@return [Template]

The new template object.

@raise [ArgumentError]

A given type is not known.

@example

template = Template[:uint32, [:char, 10]]
template.pack(0x123456, ['A', 'B', 'C'])
# => "CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00"
template.unpack("CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00")
# => [4276803, #<Ronin::Support::Binary::Array: "XYZ\x00\x00\x00\x00\x00\x00\x00">]

@see initialize

@since 1.0.0

# File lib/ronin/support/binary/template.rb, line 214
def self.[](*fields,**kwargs)
  new(fields,**kwargs)
end
new(fields, **kwargs) click to toggle source

Creates a new Binary template.

@param [::Array<Symbol, (Symbol, Integer)>] fields

The C-types which the packer will use.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments.

@option kwargs [:little, :big, :net, nil] :endian

The desired endianness of the values within the template.

@option kwargs [:x86, :x86_64,

              :ppc, :ppc64,
              :mips, :mips_le, :mips_be,
              :mips64, :mips64_le, :mips64_be,
              :arm, :arm_le, :arm_be,
              :arm64, :arm64_le, :arm64_be] :arch
The desired architecture for the values within the template.

@option kwargs [:linux, :macos, :windows,

              :android, :apple_ios, :bsd,
              :freebsd, :openbsd, :netbsd] :os
The Operating System (OS) to use.

@raise [ArgumentError]

A given type is not known.

@example

template = Template.new([:uint32, [:char, 10]])
template.pack(0x123456, ['A', 'B', 'C'])
# => "CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00"
template.unpack("CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00")
# => [4276803, #<Ronin::Support::Binary::Array: "XYZ\x00\x00\x00\x00\x00\x00\x00">]
# File lib/ronin/support/binary/template.rb, line 150
def initialize(fields, **kwargs)
  initialize_type_system(**kwargs)

  @fields = []
  @types  = []

  @pack_string = String.new

  fields.each do |field|
    type = @type_resolver.resolve(field)

    @fields      << field
    @types       << type

    if @pack_string
      if type.pack_string then @pack_string << type.pack_string
      else                     @pack_string = nil
      end
    end
  end
end

Public Instance Methods

pack(*arguments) click to toggle source

Packs the data.

@param [::Array] arguments

The values to pack.

@return [String]

The packed data.

@example

template = Template.new[:uint32, [:char, 10]]
template.pack(0x123456, ['A', 'B', 'C'])
# => "CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00"
# File lib/ronin/support/binary/template.rb, line 232
def pack(*arguments)
  if @pack_string
    values = []

    @types.each do |type|
      # shift off the next value(s) and enqueue them
      type.enqueue_value(values,arguments.shift)
    end

    values.pack(@pack_string)
  else
    buffer = String.new

    @types.each do |type|
      # shift off the next value and pack it
      buffer << type.pack(arguments.shift)
    end

    return buffer
  end
end
to_s() click to toggle source

Converts the template to a ‘Array#pack` template String.

@return [String]

The template String.

@example

template = Template.new[:uint32, [:char, 10]]
template.to_s
# => "La10"

@see rubydoc.info/stdlib/core/Array:pack

# File lib/ronin/support/binary/template.rb, line 307
def to_s
  @pack_string
end
Also aliased as: to_str
to_str()
Alias for: to_s
unpack(data) click to toggle source

Unpacks the string.

@param [String] data

The raw String to unpack.

@return [::Array]

The unpacked data.

@example

template = Template.new[:uint32, [:char, 10]]
template.unpack("CBA\x00XYZ\x00\x00\x00\x00\x00\x00\x00")
# => [4276803, #<Ronin::Support::Binary::Array: "XYZ\x00\x00\x00\x00\x00\x00\x00">]
# File lib/ronin/support/binary/template.rb, line 268
def unpack(data)
  if @pack_string
    values = data.unpack(@pack_string)

    @types.map do |type|
      type.dequeue_value(values)
    end
  else
    array  = []
    offset = 0

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

      array  << type.unpack(slice)
      offset += type.size
    end

    return array
  end
end