class BinData::IO::Read
readbits(6), readbits(5) #=> [543210, a9876]
In little endian format:
readbits(6), readbits(5) #=> [765432, 10fed]
In big endian format:
B B B B
S 76543210 S S fedcba98 S
M byte1 L M byte2 L
The IO can handle bitstreams in either big or little endian format.
wrapped in an StringIO object.
current stream position. If io
is a string it will be automatically
#pos if reading the current stream position and #seek if setting the
Create a new IO Read wrapper around io
. io
must provide #read,
def accumulate_big_endian_bits
def accumulate_big_endian_bits byte = read(1).unpack1('C') & 0xff @rval = (@rval << 8) | byte @rnbits += 8 end
def accumulate_little_endian_bits
def accumulate_little_endian_bits byte = read(1).unpack1('C') & 0xff @rval = @rval | (byte << @rnbits) @rnbits += 8 end
def initialize(io)
def initialize(io) if self.class === io raise ArgumentError, "io must not be a #{self.class}" end # wrap strings in a StringIO if io.respond_to?(:to_str) io = BinData::IO.create_string_io(io.to_str) end @io = RawIO.new(io) # bits when reading @rnbits = 0 @rval = 0 @rendian = nil end
def mask(nbits)
def mask(nbits) (1 << nbits) - 1 end
def num_bytes_remaining
def num_bytes_remaining @io.num_bytes_remaining end
def read(n = nil)
def read(n = nil) str = @io.read(n) if n raise EOFError, "End of file reached" if str.nil? raise IOError, "data truncated" if str.size < n end str end
def read_all_bytes
def read_all_bytes reset_read_bits read end
def read_big_endian_bits(nbits)
def read_big_endian_bits(nbits) while @rnbits < nbits accumulate_big_endian_bits end val = (@rval >> (@rnbits - nbits)) & mask(nbits) @rnbits -= nbits @rval &= mask(@rnbits) val end
def read_little_endian_bits(nbits)
def read_little_endian_bits(nbits) while @rnbits < nbits accumulate_little_endian_bits end val = @rval & mask(nbits) @rnbits -= nbits @rval >>= nbits val end
def readbits(nbits, endian)
Reads exactly +nbits+ bits from the stream. +endian+ specifies whether
def readbits(nbits, endian) if @rendian != endian # don't mix bits of differing endian reset_read_bits @rendian = endian end if endian == :big read_big_endian_bits(nbits) else read_little_endian_bits(nbits) end end
def readbytes(n)
If the data read is nil an EOFError is raised.
Reads exactly +n+ bytes from +io+.
def readbytes(n) reset_read_bits read(n) end
def reset_read_bits
Discards any read bits so the stream becomes aligned at the
def reset_read_bits @rnbits = 0 @rval = 0 end
def seek_to_abs_offset(n)
def seek_to_abs_offset(n) reset_read_bits @io.seek_abs(n) end
def skipbytes(n)
def skipbytes(n) reset_read_bits @io.skip(n) end
def transform(io)
+io+ must be an instance of +Transform+.
See +BinData::Buffer+ as an example.
Allow transforming data in the input stream.
def transform(io) reset_read_bits saved = @io @io = io.prepend_to_chain(@io) yield(self, io) io.after_read_transform ensure @io = saved end