Class: BinData::IO
- Inherits:
-
Object
- Object
- BinData::IO
- Defined in:
- lib/bindata/io.rb
Overview
A wrapper around an IO object. The wrapper provides a consistent interface for BinData objects to use when accessing the IO.
Instance Attribute Summary collapse
-
#raw_io ⇒ Object
readonly
Access to the underlying raw io.
Instance Method Summary collapse
-
#flushbits ⇒ Object
(also: #flush)
To be called after all
writebitshave been applied. -
#initialize(io) ⇒ IO
constructor
Create a new IO wrapper around
io. -
#offset ⇒ Object
Returns the current offset of the io stream.
-
#read_all_bytes ⇒ Object
Reads all remaining bytes from the stream.
-
#readbits(nbits, endian) ⇒ Object
Reads exactly
nbitsbits from the stream. -
#readbytes(n) ⇒ Object
Reads exactly
nbytes fromio. -
#seekbytes(n) ⇒ Object
Seek
nbytes from the current position in the io stream. -
#writebits(val, nbits, endian) ⇒ Object
Writes
nbitsbits fromvalto the stream. -
#writebytes(str) ⇒ Object
Writes the given string of bytes to the io stream.
Constructor Details
#initialize(io) ⇒ IO
Create a new IO wrapper around io. io must support #read if used for reading, #write if used for writing, #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]
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/bindata/io.rb', line 23 def initialize(io) raise ArgumentError, "io must not be a BinData::IO" if BinData::IO === io # wrap strings in a StringIO if io.respond_to?(:to_str) io = StringIO.new(io) end @raw_io = io # initial stream position if stream supports positioning @initial_pos = positioning_supported? ? io.pos : 0 # bits when reading @rnbits = 0 @rval = 0 @rendian = nil # bits when writing @wnbits = 0 @wval = 0 @wendian = nil end |
Instance Attribute Details
#raw_io ⇒ Object (readonly)
Access to the underlying raw io.
48 49 50 |
# File 'lib/bindata/io.rb', line 48 def raw_io @raw_io end |
Instance Method Details
#flushbits ⇒ Object Also known as: flush
To be called after all writebits have been applied.
133 134 135 136 137 138 139 |
# File 'lib/bindata/io.rb', line 133 def flushbits raise "Internal state error nbits = #{@wnbits}" if @wnbits >= 8 if @wnbits > 0 writebits(0, 8 - @wnbits, @wendian) end end |
#offset ⇒ Object
Returns the current offset of the io stream. The exact value of the offset when reading bitfields is not defined.
52 53 54 55 56 57 58 |
# File 'lib/bindata/io.rb', line 52 def offset if positioning_supported? @raw_io.pos - @initial_pos else 0 end end |
#read_all_bytes ⇒ Object
Reads all remaining bytes from the stream.
82 83 84 85 86 87 88 |
# File 'lib/bindata/io.rb', line 82 def read_all_bytes raise "Internal state error nbits = #{@rnbits}" if @rnbits >= 8 @rnbits = 0 @rval = 0 @raw_io.read end |
#readbits(nbits, endian) ⇒ Object
Reads exactly nbits bits from the stream. endian specifies whether the bits are stored in :big or :little endian format.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/bindata/io.rb', line 92 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_big_endian_bits(nbits) else read_little_endian_bits(nbits) end end |
#readbytes(n) ⇒ Object
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.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/bindata/io.rb', line 70 def readbytes(n) 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 |
#seekbytes(n) ⇒ Object
Seek n bytes from the current position in the io stream.
61 62 63 |
# File 'lib/bindata/io.rb', line 61 def seekbytes(n) @raw_io.seek(n, ::IO::SEEK_CUR) end |
#writebits(val, nbits, endian) ⇒ Object
Writes nbits bits from val to the stream. endian specifies whether the bits are to be stored in :big or :little endian format.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/bindata/io.rb', line 115 def writebits(val, nbits, endian) if @wendian != endian # don't mix bits of differing endian flushbits @wendian = endian end clamped_val = val & mask(nbits) if endian == :big write_big_endian_bits(clamped_val, nbits) else write_little_endian_bits(clamped_val, nbits) end end |
#writebytes(str) ⇒ Object
Writes the given string of bytes to the io stream.
108 109 110 111 |
# File 'lib/bindata/io.rb', line 108 def writebytes(str) flushbits @raw_io.write(str) end |