Class: BinData::DelayedIO
- Extended by:
- DSLMixin
- Defined in:
- lib/bindata/delayed_io.rb
Overview
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: -> { total_size - 1 }
uint8 :len, value: -> { 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.
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
- #abs_offset ⇒ Object
-
#abs_offset=(offset) ⇒ Object
Sets the
abs_offset
to use when writing this object. - #assign(val) ⇒ Object
- #clear? ⇒ Boolean
-
#do_num_bytes ⇒ Object
:nodoc:.
-
#do_read(io) ⇒ Object
:nodoc:.
-
#do_write(io) ⇒ Object
:nodoc:.
- #include_obj? ⇒ Boolean
- #initialize_instance ⇒ Object
-
#method_missing(symbol, *args, &block) ⇒ Object
:nodoc:.
- #num_bytes ⇒ Object
-
#read_now! ⇒ Object
DelayedIO objects aren’t read when #read is called.
- #rel_offset ⇒ Object
-
#respond_to_missing?(symbol, include_all = false) ⇒ Boolean
:nodoc:.
- #snapshot ⇒ Object
-
#write_now! ⇒ Object
DelayedIO objects aren’t written when #write is called.
Methods included from DSLMixin
Methods inherited from Base
#==, #=~, arg_processor, auto_call_delayed_io, bindata_name, #clear, #debug_name, #eval_parameter, #get_parameter, #has_parameter?, #initialize_with_warning, #inspect, #lazy_evaluator, #new, #pretty_print, #read, read, register_subclasses, #safe_respond_to?, #to_binary_s, #to_hex, #to_s, unregister_self, #write
Methods included from AcceptedParametersPlugin
#accepted_parameters, #default_parameters, #mandatory_parameters, #mutually_exclusive_parameters, #optional_parameters
Methods included from RegisterNamePlugin
included, #initialize_shared_instance
Methods included from Framework
#bit_aligned?, #debug_name_of, #offset_of
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args, &block) ⇒ Object
:nodoc:
90 91 92 |
# File 'lib/bindata/delayed_io.rb', line 90 def method_missing(symbol, *args, &block) # :nodoc: @type.__send__(symbol, *args, &block) end |
Instance Method Details
#abs_offset ⇒ Object
94 95 96 |
# File 'lib/bindata/delayed_io.rb', line 94 def abs_offset @abs_offset || eval_parameter(:read_abs_offset) end |
#abs_offset=(offset) ⇒ Object
Sets the abs_offset
to use when writing this object.
99 100 101 |
# File 'lib/bindata/delayed_io.rb', line 99 def abs_offset=(offset) @abs_offset = offset end |
#assign(val) ⇒ Object
74 75 76 |
# File 'lib/bindata/delayed_io.rb', line 74 def assign(val) @type.assign(val) end |
#clear? ⇒ Boolean
70 71 72 |
# File 'lib/bindata/delayed_io.rb', line 70 def clear? @type.clear? end |
#do_num_bytes ⇒ Object
:nodoc:
115 116 117 |
# File 'lib/bindata/delayed_io.rb', line 115 def do_num_bytes # :nodoc: 0 end |
#do_read(io) ⇒ Object
:nodoc:
107 108 109 |
# File 'lib/bindata/delayed_io.rb', line 107 def do_read(io) # :nodoc: @read_io = io end |
#do_write(io) ⇒ Object
:nodoc:
111 112 113 |
# File 'lib/bindata/delayed_io.rb', line 111 def do_write(io) # :nodoc: @write_io = io end |
#include_obj? ⇒ Boolean
119 120 121 |
# File 'lib/bindata/delayed_io.rb', line 119 def include_obj? !has_parameter?(:onlyif) || eval_parameter(:onlyif) end |
#initialize_instance ⇒ Object
63 64 65 66 67 68 |
# 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 |
#num_bytes ⇒ Object
82 83 84 |
# File 'lib/bindata/delayed_io.rb', line 82 def num_bytes @type.num_bytes end |
#read_now! ⇒ Object
DelayedIO objects aren’t read when #read is called. The reading is delayed until this method is called.
125 126 127 128 129 130 131 132 133 |
# File 'lib/bindata/delayed_io.rb', line 125 def read_now! return unless include_obj? raise IOError, "read from where?" unless @read_io @read_io.seek_to_abs_offset(abs_offset) start_read do @type.do_read(@read_io) end end |
#rel_offset ⇒ Object
103 104 105 |
# File 'lib/bindata/delayed_io.rb', line 103 def rel_offset abs_offset end |
#respond_to_missing?(symbol, include_all = false) ⇒ Boolean
:nodoc:
86 87 88 |
# File 'lib/bindata/delayed_io.rb', line 86 def respond_to_missing?(symbol, include_all = false) # :nodoc: @type.respond_to?(symbol, include_all) || super end |
#snapshot ⇒ Object
78 79 80 |
# File 'lib/bindata/delayed_io.rb', line 78 def snapshot @type.snapshot end |
#write_now! ⇒ Object
DelayedIO objects aren’t written when #write is called. The writing is delayed until this method is called.
137 138 139 140 141 142 143 |
# File 'lib/bindata/delayed_io.rb', line 137 def write_now! return unless include_obj? raise IOError, "write to where?" unless @write_io @write_io.seek_to_abs_offset(abs_offset) @type.do_write(@write_io) end |