class MachO::MachOStructure
A general purpose pseudo-structure. Described in detail in docs/machostructure-dsl.md. @abstract
Attributes
Public Class Methods
# File lib/macho/structure.rb, line 108 def bytesize @bytesize ||= @size_list.sum end
# File lib/macho/structure.rb, line 104 def format @format ||= @fmt_list.join end
@param args [Array] list of field parameters
# File lib/macho/structure.rb, line 75 def initialize(*args) raise ArgumentError, "Invalid number of arguments" if args.size < self.class.min_args @values = args end
@param endianness [Symbol] either ‘:big` or `:little` @param bin [String] the string to be unpacked into the new structure @return [MachO::MachOStructure] the resulting structure @api private
# File lib/macho/structure.rb, line 98 def new_from_bin(endianness, bin) format = Utils.specialize_format(self.format, endianness) new(*bin.unpack(format)) end
Private Class Methods
Generates a reader method for classes that need to be initialized. These classes are defined in the Fields::CLASSES_TO_INIT array. @param name [Symbol] name of internal field @param type [Symbol] type of field in terms of binary size @param idx [Integer] the index of the field value in the @values array @api private
# File lib/macho/structure.rb, line 196 def def_class_reader(name, type, idx) case type when :lcstr define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", LoadCommands::LoadCommand::LCStr.new(self, @values[idx])) instance_variable_get("@#{name}") end when :two_level_hints_table define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", LoadCommands::TwolevelHintsCommand::TwolevelHintsTable.new(view, htoffset, nhints)) instance_variable_get("@#{name}") end when :tool_entries define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", LoadCommands::BuildVersionCommand::ToolEntries.new(view, @values[idx])) instance_variable_get("@#{name}") end end end
Generates a reader method for fields that have default values. @param name [Symbol] name of internal field @param idx [Integer] the index of the field value in the @values array @param default [Value] the default value @api private
# File lib/macho/structure.rb, line 255 def def_default_reader(name, idx, default) define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", @values.size > idx ? @values[idx] : default) instance_variable_get("@#{name}") end end
Generates a reader method for fields that need to be bitmasked. @param name [Symbol] name of internal field @param idx [Integer] the index of the field value in the @values array @param mask [Integer] the bitmask @api private
# File lib/macho/structure.rb, line 227 def def_mask_reader(name, idx, mask) define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", @values[idx] & ~mask) instance_variable_get("@#{name}") end end
Generates an attr_reader like method for a field. @param name [Symbol] name of internal field @param idx [Integer] the index of the field value in the @values array @api private
# File lib/macho/structure.rb, line 268 def def_reader(name, idx) define_method(name) do @values[idx] end end
Generates the to_s method based on the named field. @param name [Symbol] name of the field @api private
# File lib/macho/structure.rb, line 277 def def_to_s(name) define_method(:to_s) do send(name).to_s end end
Generates a reader method for fields that need further unpacking. @param name [Symbol] name of internal field @param idx [Integer] the index of the field value in the @values array @param unpack [String] the format code used for further binary unpacking @api private
# File lib/macho/structure.rb, line 241 def def_unpack_reader(name, idx, unpack) define_method(name) do instance_variable_defined?("@#{name}") || instance_variable_set("@#{name}", @values[idx].unpack(unpack)) instance_variable_get("@#{name}") end end
@param name [Symbol] name of internal field @param type [Symbol] type of field in terms of binary size @param options [Hash] set of additional options Expected options
:size [Integer] size in bytes :mask [Integer] bitmask :unpack [String] string format :default [Value] default value :to_s [Boolean] flag for generating #to_s :endian [Symbol] optionally specify :big or :little endian :padding [Symbol] optionally specify :null padding
@api private
# File lib/macho/structure.rb, line 144 def field(name, type, **options) raise ArgumentError, "Invalid field type #{type}" unless Fields::FORMAT_CODE.key?(type) # Get field idx for size_list and fmt_list idx = if @field_idxs.key?(name) @field_idxs[name] else @min_args += 1 unless options.key?(:default) || Fields::NO_ARG_REQUIRED.include?(type) @field_idxs[name] = @field_idxs.size @size_list << nil @fmt_list << nil @field_idxs.size - 1 end # Update string type if padding is specified type = :null_padded_string if type == :string && options[:padding] == :null # Add to size_list and fmt_list @size_list[idx] = Fields::BYTE_SIZE[type] || options[:size] @fmt_list[idx] = if options[:endian] Utils.specialize_format(Fields::FORMAT_CODE[type], options[:endian]) else Fields::FORMAT_CODE[type] end @fmt_list[idx] += options[:size].to_s if options.key?(:size) # Generate methods if Fields::CLASSES_TO_INIT.include?(type) def_class_reader(name, type, idx) elsif options.key?(:mask) def_mask_reader(name, idx, options[:mask]) elsif options.key?(:unpack) def_unpack_reader(name, idx, options[:unpack]) elsif options.key?(:default) def_default_reader(name, idx, options[:default]) else def_reader(name, idx) end def_to_s(name) if options[:to_s] end
@param subclass [Class] subclass type @api private
# File lib/macho/structure.rb, line 116 def inherited(subclass) # rubocop:disable Lint/MissingSuper # Clone all class instance variables field_idxs = @field_idxs.dup size_list = @size_list.dup fmt_list = @fmt_list.dup min_args = @min_args.dup # Add those values to the inheriting class subclass.class_eval do @field_idxs = field_idxs @size_list = size_list @fmt_list = fmt_list @min_args = min_args end end
Public Instance Methods
@return [Hash] a hash representation of this {MachOStructure}.
# File lib/macho/structure.rb, line 82 def to_h { "structure" => { "format" => self.class.format, "bytesize" => self.class.bytesize, }, } end