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