class Bistro

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/bistro.rb, line 153
def self.clear_structs_by_definition_cache
  @@structs_by_definition.clear
end
decode(data, definition) click to toggle source
# File lib/bistro.rb, line 161
def self.decode(data, definition)
  struct_by_definition(definition).decode(data)
end
encode(hash, definition) click to toggle source
# File lib/bistro.rb, line 165
def self.encode(hash, definition)
  struct_by_definition(definition).encode(hash)
end
new(definition = nil) click to toggle source
# File lib/bistro.rb, line 49
def initialize(definition = nil)
  self.definition = definition unless definition.nil?
end
sizeof(definition) click to toggle source
# File lib/bistro.rb, line 157
def self.sizeof(definition)
  struct_by_definition(definition).size
end

Private Class Methods

get_size(definition) click to toggle source
# File lib/bistro.rb, line 225
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/bistro.rb, line 247
def self.prep_decode(definition)
  formats = ""
    types = []
    names = []
   counts = []

  definition.each_slice(2) do |format, name|
           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 =        1 if count.empty?

      types << type
    formats << format
      names << name
     counts << count
  end

  return types, formats, names, counts
end
struct_by_definition(definition) click to toggle source
# File lib/bistro.rb, line 171
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/bistro.rb, line 212
def self.valid_definition_entry_modifier?(modifier)
  MODIFIERS.include? modifier
end
validate_definition(definition) click to toggle source
# File lib/bistro.rb, line 177
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/bistro.rb, line 216
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/bistro.rb, line 201
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/bistro.rb, line 195
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/bistro.rb, line 139
def ==(other)
  self.definition == other.definition
end
decode(data, num = 1) click to toggle source
# File lib/bistro.rb, line 76
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/bistro.rb, line 85
def decode_to_array(data, num = 1)
  raise ArgumentError, "data cannot be nil" if data.nil?
  @decode_types, @decode_formats,
  @decode_names, @decode_counts =
    self.class.prep_decode(@definition) if @decode_formats.nil?

  format = (num == 1) ? @decode_formats : @decode_formats * num
  return data.unpack(format)
end
decoded_array_to_hash!(array) click to toggle source
# File lib/bistro.rb, line 95
def decoded_array_to_hash!(array)
  hash = {}
  @decode_names.each_with_index do |k,i|
    c = @decode_counts[i].to_i
    t = @decode_types[i]

    v = nil
    if !STRING_FORMATS.include?(t) && c != 1
      v = 0.upto(c-1).collect { array.shift }
    else
      v = array.shift
    end

    next if k.nil?
    hash[k] = v
  end
  return hash
end
definition() click to toggle source
# File lib/bistro.rb, line 53
def definition
  @definition
end
definition=(value) click to toggle source
# File lib/bistro.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_types = @decode_formats =
  @decode_names = @decode_counts = nil
end
each(&block) click to toggle source
# File lib/bistro.rb, line 143
def each(&block)
  self.definition.each_slice(2, &block)
end
encode(hash) click to toggle source
# File lib/bistro.rb, line 114
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/bistro.rb, line 122
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/bistro.rb, line 72
def size
  @size ||= self.class.get_size(@definition)
end