lib/bindata/io.rb in bindata-0.9.3 vs lib/bindata/io.rb in bindata-0.10.0
- old
+ new
@@ -51,11 +51,10 @@
# the offset when reading bitfields is not defined.
def offset
if positioning_supported?
@raw_io.pos - @initial_pos
else
- # stream does not support positioning
0
end
end
# Seek +n+ bytes from the current position in the io stream.
@@ -67,34 +66,43 @@
#
# If the data read is nil an EOFError is raised.
#
# If the data read is too short an IOError is raised.
def readbytes(n)
- raise "Internal state error nbits = #{@rnbits}" if @rnbits > 8
+ raise "Internal state error nbits = #{@rnbits}" if @rnbits >= 8
@rnbits = 0
@rval = 0
str = @raw_io.read(n)
raise EOFError, "End of file reached" if str.nil?
raise IOError, "data truncated" if str.size < n
str
end
+ # Reads all remaining bytes from the stream.
+ def read_all_bytes
+ raise "Internal state error nbits = #{@rnbits}" if @rnbits >= 8
+ @rnbits = 0
+ @rval = 0
+
+ @raw_io.read
+ end
+
# Reads exactly +nbits+ bits from the stream. +endian+ specifies whether
# the bits are stored in +:big+ or +:little+ endian format.
- def readbits(nbits, endian = :big)
+ def readbits(nbits, endian)
if @rendian != endian
# don't mix bits of differing endian
@rnbits = 0
@rval = 0
@rendian = endian
end
if endian == :big
- read_be_bits(nbits)
+ read_big_endian_bits(nbits)
else
- read_le_bits(nbits)
+ read_little_endian_bits(nbits)
end
end
# Writes the given string of bytes to the io stream.
def writebytes(str)
@@ -102,44 +110,40 @@
@raw_io.write(str)
end
# Writes +nbits+ bits from +val+ to the stream. +endian+ specifies whether
# the bits are to be stored in +:big+ or +:little+ endian format.
- def writebits(val, nbits, endian = :big)
- # clamp val to range
- val = val & ((1 << nbits) - 1)
-
+ def writebits(val, nbits, endian)
if @wendian != endian
# don't mix bits of differing endian
- flushbits if @wnbits > 0
+ flushbits
@wendian = endian
end
+ clamped_val = val & mask(nbits)
+
if endian == :big
- write_be_bits(val, nbits)
+ write_big_endian_bits(clamped_val, nbits)
else
- write_le_bits(val, nbits)
+ write_little_endian_bits(clamped_val, nbits)
end
end
# To be called after all +writebits+ have been applied.
def flushbits
- if @wnbits > 8
- raise "Internal state error nbits = #{@wnbits}" if @wnbits > 8
- elsif @wnbits > 0
+ raise "Internal state error nbits = #{@wnbits}" if @wnbits >= 8
+
+ if @wnbits > 0
writebits(0, 8 - @wnbits, @wendian)
- else
- # do nothing
end
end
alias_method :flush, :flushbits
#---------------
private
- # Checks if positioning is supported by the underlying io stream.
def positioning_supported?
unless defined? @positioning_supported
@positioning_supported = begin
@raw_io.pos
true
@@ -148,56 +152,59 @@
end
end
@positioning_supported
end
- # Reads exactly +nbits+ big endian bits from the stream.
- def read_be_bits(nbits)
- # ensure enough bits have accumulated
- while nbits > @rnbits
- byte = @raw_io.read(1)
- raise EOFError, "End of file reached" if byte.nil?
- byte = byte.unpack('C').at(0) & 0xff
-
- @rval = (@rval << 8) | byte
- @rnbits += 8
+ def read_big_endian_bits(nbits)
+ while @rnbits < nbits
+ accumulate_big_endian_bits
end
- val = (@rval >> (@rnbits - nbits)) & ((1 << nbits) - 1)
+ val = (@rval >> (@rnbits - nbits)) & mask(nbits)
@rnbits -= nbits
- @rval &= ((1 << @rnbits) - 1)
+ @rval &= mask(@rnbits)
val
end
- # Reads exactly +nbits+ little endian bits from the stream.
- def read_le_bits(nbits)
- # ensure enough bits have accumulated
- while nbits > @rnbits
- byte = @raw_io.read(1)
- raise EOFError, "End of file reached" if byte.nil?
- byte = byte.unpack('C').at(0) & 0xff
+ def accumulate_big_endian_bits
+ byte = @raw_io.read(1)
+ raise EOFError, "End of file reached" if byte.nil?
+ byte = byte.unpack('C').at(0) & 0xff
- @rval = @rval | (byte << @rnbits)
- @rnbits += 8
+ @rval = (@rval << 8) | byte
+ @rnbits += 8
+ end
+
+ def read_little_endian_bits(nbits)
+ while @rnbits < nbits
+ accumulate_little_endian_bits
end
- val = @rval & ((1 << nbits) - 1)
+ val = @rval & mask(nbits)
@rnbits -= nbits
@rval >>= nbits
val
end
- # Writes +nbits+ bits from +val+ to the stream in big endian format.
- def write_be_bits(val, nbits)
+ def accumulate_little_endian_bits
+ byte = @raw_io.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 write_big_endian_bits(val, nbits)
while nbits > 0
bits_req = 8 - @wnbits
if nbits >= bits_req
- msb_bits = (val >> (nbits - bits_req)) & ((1 << bits_req) - 1)
+ msb_bits = (val >> (nbits - bits_req)) & mask(bits_req)
nbits -= bits_req
- val &= (1 << nbits) - 1
+ val &= mask(nbits)
@wval = (@wval << bits_req) | msb_bits
@raw_io.write(@wval.chr)
@wval = 0
@@ -208,28 +215,31 @@
nbits = 0
end
end
end
- # Writes +nbits+ bits from +val+ to the stream in little endian format.
- def write_le_bits(val, nbits)
+ def write_little_endian_bits(val, nbits)
while nbits > 0
bits_req = 8 - @wnbits
if nbits >= bits_req
- lsb_bits = val & ((1 << bits_req) - 1)
+ lsb_bits = val & mask(bits_req)
nbits -= bits_req
val >>= bits_req
- @wval |= (lsb_bits << @wnbits)
+ @wval = @wval | (lsb_bits << @wnbits)
@raw_io.write(@wval.chr)
@wval = 0
@wnbits = 0
else
- @wval |= (val << @wnbits)
+ @wval = @wval | (val << @wnbits)
@wnbits += nbits
nbits = 0
end
end
+ end
+
+ def mask(nbits)
+ (1 << nbits) - 1
end
end
end