Class: ErlangBitstream

Inherits:
Object
  • Object
show all
Defined in:
lib/utils/erlang_parser.rb

Constant Summary collapse

TYPES =
{
  'integer' => 8,
  'float'   => 8*8,
  'utf8'    => 8,
  'utf16'   => 8*2,
  'utf32'   => 8*4,
}.freeze

Instance Method Summary collapse

Constructor Details

#initializeErlangBitstream

Returns a new instance of ErlangBitstream.



85
86
87
88
# File 'lib/utils/erlang_parser.rb', line 85

def initialize
  @data = []     # a stream of 8-bit numbers
  @cur_bits = '' # a string of binary bits 10010010...
end

Instance Method Details

#add(i) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/utils/erlang_parser.rb', line 104

def add(i)
  if i[:integer].nil? && i[:string].nil?
    raise 'No data provided, internal error for binary-stream processing!'
  end
  s = bit_size(i[:size], i[:type])
  unless i[:string].nil?
    str2int(i[:string].to_s, i[:type]).map { |e| add_bits(int2bits(e, 8)) }
  else
    add_int(i[:integer], s)
  end
rescue RuntimeError => e
  raise 'Error processing Erlang bit string '\
        "'#{i[:string] || i[:integer]}:#{i[:size]}/#{i[:type]}'. #{e.message}"
end

#add_bits(s) ⇒ Object



138
139
140
141
142
# File 'lib/utils/erlang_parser.rb', line 138

def add_bits(s)
  b = (@cur_bits + s).scan(/.{1,8}/)
  @data += b[0..-2].map { |x| x.to_i(2) }
  @cur_bits = b.last
end

#add_int(v, size) ⇒ Object



133
134
135
136
# File 'lib/utils/erlang_parser.rb', line 133

def add_int(v, size)
  x = v.to_i & (2**size - 1) # only get the bits specified in size
  add_bits(int2bits(x, size))
end

#bit_size(size, type) ⇒ Object



98
99
100
101
102
# File 'lib/utils/erlang_parser.rb', line 98

def bit_size(size, type)
  raise 'Cannot specify size and type at the same time.' if !type.nil? && !size.nil?
  return (size || 8).to_i if type.nil?
  TYPES[type] || raise("Cannot handle binary-stream type #{type}")
end

#int2bits(i, len) ⇒ Object



129
130
131
# File 'lib/utils/erlang_parser.rb', line 129

def int2bits(i, len)
  format("%0#{len}b", i)
end

#str2int(s, type) ⇒ Object



119
120
121
122
123
124
125
126
127
# File 'lib/utils/erlang_parser.rb', line 119

def str2int(s, type)
  case type
  when 'utf8' then s.encode('utf-8').unpack('C*')
  when 'utf16' then s.encode('utf-16').unpack('C*').drop(2)
  when 'utf32' then s.encode('utf-32').unpack('C*').drop(4)
  when 'integer', 'float' then raise "Cannot handle bit string as type #{type}"
  else s.split('').map { |x| x.ord & 0xff }
  end
end

#value(encoding = 'utf-8') ⇒ Object



144
145
146
147
148
149
150
151
# File 'lib/utils/erlang_parser.rb', line 144

def value(encoding = 'utf-8')
  # fill in the rest
  rest = '0' * (8 - @cur_bits.length) + @cur_bits
  arr = @data + [rest.to_i(2)]
  s = arr.pack('C*')
  s.force_encoding(encoding) unless encoding.nil?
  s
end