class BinaryStruct

Constants

BIT_FORMATS
ENDIAN_FORMATS
ENDIAN_MODIFIERS
MODIFIERS
NIBBLE_FORMATS
SIZES
STRING_FORMATS
VERSION

Public Class Methods

clear_structs_by_definition_cache() click to toggle source
# File lib/binary_struct.rb, line 135
def self.clear_structs_by_definition_cache
  @@structs_by_definition.clear
end
decode(data, definition) click to toggle source
# File lib/binary_struct.rb, line 143
def self.decode(data, definition)
  struct_by_definition(definition).decode(data)
end
encode(hash, definition) click to toggle source
# File lib/binary_struct.rb, line 147
def self.encode(hash, definition)
  struct_by_definition(definition).encode(hash)
end
new(definition = nil) click to toggle source
# File lib/binary_struct.rb, line 49
def initialize(definition = nil)
  self.definition = definition unless definition.nil?
end
sizeof(definition) click to toggle source
# File lib/binary_struct.rb, line 139
def self.sizeof(definition)
  struct_by_definition(definition).size
end

Private Class Methods

get_size(definition) click to toggle source
# File lib/binary_struct.rb, line 201
def self.get_size(definition)
  size = 0
  definition.each_slice(2) do |format, _|
    type, count        = format[0, 1], format[1..-1]
    modifier, modcount = count[0, 1], count[1..-1]
    count = modcount if valid_definition_entry_modifier?(modifier)
    count = count.empty? ? 1 : count.to_i
    size +=
      if BIT_FORMATS.include?(type)
        (count / 8.0).ceil
      elsif NIBBLE_FORMATS.include?(type)
        (count / 2.0).ceil
      else
        count * SIZES[type]
      end
  end
  size
end
prep_decode(definition) click to toggle source
# File lib/binary_struct.rb, line 220
def self.prep_decode(definition)
  formats = ""
  names = []
  definition.each_slice(2) do |format, name|
    formats << format
    names << name
  end
  return formats, names
end
struct_by_definition(definition) click to toggle source
# File lib/binary_struct.rb, line 153
def self.struct_by_definition(definition)
  @@structs_by_definition[definition] ||= definition.kind_of?(self) ? definition : self.new(definition)
end
valid_definition_entry_modifier?(modifier) click to toggle source
# File lib/binary_struct.rb, line 189
def self.valid_definition_entry_modifier?(modifier)
  MODIFIERS.include? modifier
end
validate_definition(definition) click to toggle source
# File lib/binary_struct.rb, line 157
def self.validate_definition(definition)
  raise "definition must be an array of format/name pairs" if definition.empty? || definition.length % 2 != 0
  definition.each_slice(2) do |format, _|
    type, count = format[0, 1], format[1..-1]
    modifier, modcount = count[0, 1], count[1..-1]
    validate_definition_entry_type(type)
    if valid_definition_entry_modifier?(modifier)
      validate_definition_endian_modifier(modifier, type)
      validate_definition_entry_count(modcount)
    else
      validate_definition_entry_count(count)
    end
  end
end
validate_definition_endian_modifier(modifier, type) click to toggle source
# File lib/binary_struct.rb, line 193
def self.validate_definition_endian_modifier(modifier, type)
  if ENDIAN_MODIFIERS.include? modifier
    raise "unsupported type attribute #{type} for endian modifier #{modifier}" unless ENDIAN_FORMATS.include? type
    return true
  end
  false
end
validate_definition_entry_count(count) click to toggle source
# File lib/binary_struct.rb, line 178
def self.validate_definition_entry_count(count)
  return true if count.empty? || count == '*'

  begin
    count = Integer(count)
  rescue
    raise "unsupported count: #{count}"
  end
  raise "unsupported count: #{count}" if count < 0
end
validate_definition_entry_type(type) click to toggle source
# File lib/binary_struct.rb, line 172
def self.validate_definition_entry_type(type)
  raise "unrecognized format: #{type}" unless SIZES.has_key?(type)
  raise "unsupported format: #{type}" if SIZES[type].nil?
  return true
end

Public Instance Methods

==(other) click to toggle source
# File lib/binary_struct.rb, line 121
def ==(other)
  self.definition == other.definition
end
decode(data, num = 1) click to toggle source
# File lib/binary_struct.rb, line 73
def decode(data, num = 1)
  values = self.decode_to_array(data, num)
  return self.decoded_array_to_hash!(values) if num == 1

  result = []
  num.times { result << self.decoded_array_to_hash!(values) }
  return result
end
decode_to_array(data, num = 1) click to toggle source
# File lib/binary_struct.rb, line 82
def decode_to_array(data, num = 1)
  raise ArgumentError, "data cannot be nil" if data.nil?
  @decode_format, @decode_names = self.class.prep_decode(@definition) if @decode_format.nil?
  format = (num == 1) ? @decode_format : @decode_format * num
  return data.unpack(format)
end
decoded_array_to_hash!(array) click to toggle source
# File lib/binary_struct.rb, line 89
def decoded_array_to_hash!(array)
  hash = {}
  @decode_names.each do |k|
    v = array.shift
    next if k.nil?
    hash[k] = v
  end
  return hash
end
definition() click to toggle source
# File lib/binary_struct.rb, line 53
def definition
  @definition
end
definition=(value) click to toggle source
# File lib/binary_struct.rb, line 57
def definition=(value)
  if value.kind_of?(self.class)
    @definition = value.definition.dup
  else
    value = value.to_a.map(&:reverse).flatten if value.kind_of?(Hash)
    value = Array(value)
    self.class.validate_definition(value)
    @definition = value
  end
  @size = @decode_format = @decode_name = nil
end
each(&block) click to toggle source
# File lib/binary_struct.rb, line 125
def each(&block)
  self.definition.each_slice(2, &block)
end
encode(hash) click to toggle source
# File lib/binary_struct.rb, line 99
def encode(hash)
  return encode_hash(hash) unless hash.kind_of?(Array)

  data = ""
  hash.each { |h| data << self.encode_hash(h) }
  return data
end
encode_hash(hash) click to toggle source
# File lib/binary_struct.rb, line 107
def encode_hash(hash)
  data = ""
  @definition.each_slice(2) do |format, name|
    raise "member not found: #{name}" unless name.nil? || hash.has_key?(name)
    value = unless name.nil?
      hash[name]
    else
      STRING_FORMATS.include?(format[0, 1]) ? '0' : 0
    end
    data << [value].pack(format)
  end
  return data
end
size() click to toggle source
# File lib/binary_struct.rb, line 69
def size
  @size ||= self.class.get_size(@definition)
end