#! /usr/local/bin/ruby class BitIO def initialize(data) @data = data @byte_offset = 0 @bit_offset = 0 end def set_offset!(byte_offset, bit_offset) @byte_offset = byte_offset @bit_offset = bit_offset end def incr_offset!(byte_width, bit_width) @byte_offset = @byte_offset + byte_width @bit_offset = @bit_offset + bit_width while (7 < @bit_offset) @byte_offset = @byte_offset + 1; @bit_offset = @bit_offset - 8; end end # peek bit def get_bit(byte_offset=@byte_offset, bit_offset=@bit_offset) if (@data.length <= byte_offset) return -1; end if RUBY_VERSION >= '1.9.0' # >_<; byte = @data[byte_offset].ord else byte = @data[byte_offset] end (byte >> (7 - @bit_offset)) & 1 end # get and incr bit def get_bit! bit = get_bit() if (0 <= bit) incr_offset!(0, 1) end bit end # get bits value def get_bits!(bit_width) byte = 0 (1..bit_width).each { bit = get_bit!() byte = byte << 1 byte = byte | bit } byte end def get_bits_signed!(bit_width) bits = get_bits!(bit_width) sig_b = 1 << (bit_width - 1) if (sig_b & bits) # negaive bit_mask = (sig_b << 1) - 1 bits = bits ^ bit_mask; # bit reverse bits = - (bits + 1) end bits end def each @data.each_byte { |byte| (0..7).each { |bit_offset| bit = (byte >> (7 - bit_offset)) & 1 yield(bit) } } end end # test routine data = "foobaabaz" $io = BitIO.new(data) v1= $io.get_bits!(5) v2 = $io.get_bits_signed!(3) printf("%d %d\n", v1, v2) $io.set_offset!(0,0); $io.each { |b| printf("%d", b) } puts("\n"); data.each_byte { |b| (1..8).each { bit = $io.get_bit!() printf("%d", bit); } printf(" %c\n", b); }