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.
Class Method Summary collapse
-
.create_string_io(str = "") ⇒ Object
Creates a StringIO around
str.
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. -
#num_bytes_remaining ⇒ Object
The number of bytes remaining in the input stream.
-
#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. -
#reset_read_bits ⇒ Object
Discards any read bits so the stream becomes aligned at the next byte boundary.
-
#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]
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/bindata/io.rb', line 33 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 = BinData::IO.create_string_io(io.to_str) 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.
58 59 60 |
# File 'lib/bindata/io.rb', line 58 def raw_io @raw_io end |
Class Method Details
.create_string_io(str = "") ⇒ Object
Creates a StringIO around str.
9 10 11 12 13 14 |
# File 'lib/bindata/io.rb', line 9 def self.create_string_io(str = "") if str.respond_to?(:force_encoding) str = str.dup.force_encoding(Encoding::BINARY) end StringIO.new(str) end |
Instance Method Details
#flushbits ⇒ Object Also known as: flush
To be called after all writebits have been applied.
161 162 163 164 165 166 167 |
# File 'lib/bindata/io.rb', line 161 def flushbits raise "Internal state error nbits = #{@wnbits}" if @wnbits >= 8 if @wnbits > 0 writebits(0, 8 - @wnbits, @wendian) end end |
#num_bytes_remaining ⇒ Object
The number of bytes remaining in the input stream.
71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/bindata/io.rb', line 71 def num_bytes_remaining if positioning_supported? pos = @raw_io.pos @raw_io.seek(0, ::IO::SEEK_END) bytes_remaining = @raw_io.pos - pos @raw_io.seek(pos, ::IO::SEEK_SET) bytes_remaining else 0 end end |
#offset ⇒ Object
Returns the current offset of the io stream. The exact value of the offset when reading bitfields is not defined.
62 63 64 65 66 67 68 |
# File 'lib/bindata/io.rb', line 62 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.
107 108 109 110 |
# File 'lib/bindata/io.rb', line 107 def read_all_bytes reset_read_bits @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.
114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/bindata/io.rb', line 114 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) ⇒ 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.
97 98 99 100 101 102 103 104 |
# File 'lib/bindata/io.rb', line 97 def readbytes(n) reset_read_bits str = @raw_io.read(n) raise EOFError, "End of file reached" if str.nil? raise IOError, "data truncated" if str.size < n str end |
#reset_read_bits ⇒ Object
Discards any read bits so the stream becomes aligned at the next byte boundary.
130 131 132 133 134 |
# File 'lib/bindata/io.rb', line 130 def reset_read_bits raise "Internal state error nbits = #{@rnbits}" if @rnbits >= 8 @rnbits = 0 @rval = 0 end |
#seekbytes(n) ⇒ Object
Seek n bytes from the current position in the io stream.
85 86 87 88 89 90 |
# File 'lib/bindata/io.rb', line 85 def seekbytes(n) reset_read_bits @raw_io.seek(n, ::IO::SEEK_CUR) rescue NoMethodError, Errno::ESPIPE, Errno::EPIPE skipbytes(n) 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.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/bindata/io.rb', line 144 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.
137 138 139 140 |
# File 'lib/bindata/io.rb', line 137 def writebytes(str) flushbits @raw_io.write(str) end |