Class: BitUnpacker

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

Overview

The BitUnPacker class unpacks the byte-packed format used in Flash files. In most cases data types are stored as a number of complete bytes, in file formats where size matters a lot some people choose to store information as packed bytes. This means that the boundary of a value can lie within a byte.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bytes, size, parts = nil, skip = nil) ⇒ BitUnpacker

Initialize a new BitUnpacker, note that the BitUnpacker is a parse class with a lot of internal state variables. You probably only want to use the class methods.

bytes: A string with the bytes to unpack size: The number of bits per entry parts: The number of entries to unpack from the string, default is (bytes.length*8)/size skip: The number of bits to skip from the start of the string, default is 0



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/bit_unpacker.rb', line 12

def initialize(bytes, size, parts=nil, skip=nil)
  # Input
  @bytes = bytes
  @size = size
  @parts = parts || (bytes.length*8)/size
  @skip = skip || 0
  # Reader state
  @bytes_offset = 0
  @current = @bytes[0]
  @have = 8
  if @skip
    # TODO: skip more than 8 bytes
    take @skip
    @have -= @skip
  end
end

Class Method Details

.uunpack(bytes, size, parts = nil, skip = nil) ⇒ Object

Unpack a byte-packed string and interpret the values as a signed integer

bytes: A string with the bytes to unpack size: The number of bits per entry parts: The number of entries to unpack from the string, default is (bytes.length*8)/size skip: The number of bits to skip from the start of the string, default is 0



71
72
73
# File 'lib/bit_unpacker.rb', line 71

def self.uunpack(bytes, size, parts=nil, skip=nil)
  BitUnpacker.new(bytes, size, parts, skip).uunpack
end

Instance Method Details

#take(bits) ⇒ Object

Take a number of bits from the current byte and shift them away



30
31
32
33
34
# File 'lib/bit_unpacker.rb', line 30

def take(bits)
  value = @current >> 8 - bits
  @current = (@current & (0xff >> bits)) << bits
  value
end

#uunpackObject

Unpack by treating every consecutive block of bits as a signed integer



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/bit_unpacker.rb', line 37

def uunpack
  unpacked = []
  value = 0
  @parts.times do
    # It's signed, so we need the first byte to determine the sign
    want = @size - 1
    is_negative = take(1) == 1 ? true : false
    @have -= 1
    while want > 0
      if want < @have
        value = (value << want) + take(want)
        @have -= want
        want = 0
      else # want > @have
        value = (value << @have) + take(@have)
        want -= @have
        @have = 8
        
        @bytes_offset += 1
        @current = @bytes[@bytes_offset]
      end
    end
    unpacked << (is_negative ? -value : value)
    value = 0
  end
  unpacked
end