class BinData::IO::Read

Create a new IO Read wrapper around io. io must provide read, pos if reading the current stream position and seek if setting the current stream position. If io is a string it will be automatically wrapped in an StringIO object.

The IO can handle bitstreams in either big or little endian format.

M  byte1   L      M  byte2   L
S 76543210 S      S fedcba98 S
B          B      B          B

In big endian format:

readbits(6), readbits(5) #=> [765432, 10fed]

In little endian format:

readbits(6), readbits(5) #=> [543210, a9876]

Public Class Methods

new(io) click to toggle source
Calls superclass method BinData::IO::Common.new
# File lib/bindata/io.rb, line 173
def initialize(io)
  super(io)

  # bits when reading
  @rnbits  = 0
  @rval    = 0
  @rendian = nil
end

Public Instance Methods

offset() click to toggle source

Returns the current offset of the io stream. Offset will be rounded up when reading bitfields.

# File lib/bindata/io.rb, line 193
def offset
  offset_raw
end
read_all_bytes() click to toggle source

Reads all remaining bytes from the stream.

# File lib/bindata/io.rb, line 218
def read_all_bytes
  reset_read_bits
  read
end
readbits(nbits, endian) click to toggle source

Reads exactly nbits bits from the stream. endian specifies whether the bits are stored in :big or :little endian format.

# File lib/bindata/io.rb, line 225
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
readbytes(n) click to toggle source

Reads exactly n bytes from io.

If the data read is nil an EOFError is raised.

If the data read is too short an IOError is raised.

# File lib/bindata/io.rb, line 208
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
reset_read_bits() click to toggle source

Discards any read bits so the stream becomes aligned at the next byte boundary.

# File lib/bindata/io.rb, line 241
def reset_read_bits
  @rnbits = 0
  @rval   = 0
end
seekbytes(n) click to toggle source

Seek n bytes from the current position in the io stream.

# File lib/bindata/io.rb, line 198
def seekbytes(n)
  reset_read_bits
  seek(n)
end
with_buffer(n, &block) click to toggle source

Sets a buffer of n bytes on the io stream. Any reading or seeking calls inside the block will be contained within this buffer.

# File lib/bindata/io.rb, line 184
def with_buffer(n, &block)
  with_buffer_common(n) do
    block.call
    read
  end
end

Private Instance Methods

accumulate_big_endian_bits() click to toggle source
# File lib/bindata/io.rb, line 265
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
accumulate_little_endian_bits() click to toggle source
# File lib/bindata/io.rb, line 286
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
mask(nbits) click to toggle source
# File lib/bindata/io.rb, line 295
def mask(nbits)
  (1 << nbits) - 1
end
read(n = nil) click to toggle source
# File lib/bindata/io.rb, line 249
def read(n = nil)
  read_raw(buffer_limited_n(n))
end
read_big_endian_bits(nbits) click to toggle source
# File lib/bindata/io.rb, line 253
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
read_little_endian_bits(nbits) click to toggle source
# File lib/bindata/io.rb, line 274
def read_little_endian_bits(nbits)
  while @rnbits < nbits
    accumulate_little_endian_bits
  end

  val     = @rval & mask(nbits)
  @rnbits -= nbits
  @rval   >>= nbits

  val
end