class BinData::DelayedIO
BinData declarations are evaluated in a single pass. However, some binary formats require multi pass processing. A common reason is seeking backwards in the input stream.
DelayedIO supports multi pass processing. It works by ignoring the normal read or write calls. The user must explicitly call the read_now! or write_now! methods to process an additional pass. This additional pass must specify the #abs_offset of the I/O operation.
require 'bindata' obj = BinData::DelayedIO.new(:read_abs_offset => 3, :type => :uint16be) obj.read("\x00\x00\x00\x11\x12") obj #=> 0 obj.read_now! obj #=> 0x1112 - OR - obj.read("\x00\x00\x00\x11\x12") { obj.read_now! } #=> 0x1122 obj.to_binary_s { obj.write_now! } #=> "\x00\x00\x00\x11\x12"
You can use the auto_call_delayed_io
keyword to cause read and write to automatically perform the
extra passes.
class ReversePascalString < BinData::Record auto_call_delayed_io delayed_io :str, :read_abs_offset => 0 do string :read_length => :len end count_bytes_remaining :total_size skip :to_abs_offset => lambda { total_size - 1 } uint8 :len, :value => lambda { str.length } end s = ReversePascalString.read("hello\x05") s.to_binary_s #=> "hello\x05"
Parameters¶ ↑
Parameters may be provided at initialisation to control the behaviour of an object. These params are:
:read_abs_offset
-
The #abs_offset to start reading at.
:type
-
The single type inside the delayed io. Use a struct if multiple fields are required.
Public Instance Methods
# File lib/bindata/delayed_io.rb, line 94 def abs_offset @abs_offset || eval_parameter(:read_abs_offset) end
Sets the abs_offset
to use when writing this object.
# File lib/bindata/delayed_io.rb, line 99 def abs_offset=(offset) @abs_offset = offset end
# File lib/bindata/delayed_io.rb, line 74 def assign(val) @type.assign(val) end
# File lib/bindata/delayed_io.rb, line 70 def clear? @type.clear? end
# File lib/bindata/delayed_io.rb, line 63 def initialize_instance @type = get_parameter(:type).instantiate(nil, self) @abs_offset = nil @read_io = nil @write_io = nil end
# File lib/bindata/delayed_io.rb, line 82 def num_bytes @type.num_bytes end
DelayedIO objects aren't read when read is called. The reading is delayed until this method is called.
# File lib/bindata/delayed_io.rb, line 121 def read_now! raise IOError.new "read from where?" unless @read_io @read_io.seekbytes(abs_offset - @read_io.offset) start_read do @type.do_read(@read_io) end end
# File lib/bindata/delayed_io.rb, line 103 def rel_offset abs_offset end
# File lib/bindata/delayed_io.rb, line 78 def snapshot @type.snapshot end