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. -
#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]
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 RUBY_VERSION >= "1.9" 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.
139 140 141 142 143 144 145 |
# File 'lib/bindata/io.rb', line 139 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.
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.
93 94 95 96 |
# File 'lib/bindata/io.rb', line 93 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.
100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/bindata/io.rb', line 100 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.
83 84 85 86 87 88 89 90 |
# File 'lib/bindata/io.rb', line 83 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 |
#seekbytes(n) ⇒ Object
Seek n bytes from the current position in the io stream.
71 72 73 74 75 76 |
# File 'lib/bindata/io.rb', line 71 def seekbytes(n) reset_read_bits @raw_io.seek(n, ::IO::SEEK_CUR) rescue 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.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/bindata/io.rb', line 122 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.
115 116 117 118 |
# File 'lib/bindata/io.rb', line 115 def writebytes(str) flushbits @raw_io.write(str) end |