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) raise EOFError, "End of file reached" if byte.nil? byte = byte.unpack('C').at(0) & 0xff @rval = (@rval << 8) | byte @rnbits += 8 end
def accumulate_little_endian_bits
def accumulate_little_endian_bits byte = read(1) raise EOFError, "End of file reached" if byte.nil? byte = byte.unpack('C').at(0) & 0xff @rval = @rval | (byte << @rnbits) @rnbits += 8 end
def buffer_limited_n(n)
def buffer_limited_n(n) if @buffer_end_pos max = @buffer_end_pos - offset n = max if n.nil? or n > max end n end
def initialize(io)
def initialize(io) raise ArgumentError, "io must not be a BinData::IO::Read" if BinData::IO::Read === io # wrap strings in a StringIO if io.respond_to?(:to_str) io = BinData::IO.create_string_io(io.to_str) end @raw_io = io # bits when reading @rnbits = 0 @rval = 0 @rendian = nil @buffer_end_pos = nil extend seekable? ? SeekableStream : UnSeekableStream end
def mask(nbits)
def mask(nbits) (1 << nbits) - 1 end
def read(n = nil)
def read(n = nil) read_raw(buffer_limited_n(n)) 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 str = read(n) raise EOFError, "End of file reached" if str.nil? raise IOError, "data truncated" if str.size < n str 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(n)
def seek(n) seek_raw(buffer_limited_n(n)) end
def seekable?
def seekable? @raw_io.pos rescue NoMethodError, Errno::ESPIPE, Errno::EPIPE nil end
def seekbytes(n)
def seekbytes(n) reset_read_bits seek(n) end
def with_buffer(n, &block)
Sets a buffer of +n+ bytes on the io stream. Any reading or seeking
def with_buffer(n, &block) prev = @buffer_end_pos if prev avail = prev - offset n = avail if n > avail end @buffer_end_pos = offset + n begin block.call read ensure @buffer_end_pos = prev end end