class BinData::Struct
- nested data objects.
endian of any numerics in this struct, or in any:endian
- Either :little or :big. This specifies the default
by name.
in #snapshot or #field_names but are still accessible
from the outside world. Hidden fields don’t appear:hide
- A list of the names of fields that are to be hidden
when instantiating it.
optional hash of parameters to pass to this field
type. Name is the name of this field. Params is an
params]. Type is a symbol representing a registered
Each element of the array is of the form [type, name,:fields
-
An array specifying the fields for this struct.
an object. These params are:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
obj.field_names =># [“b”, “s”]
[:tuple, :s] ])
[:int16le, :b],
:fields => [ [:int32le, :a],
obj = BinData::Struct.new(:hide => :a,
end
int8 :z
int8 :y
int8 :x
class Tuple < BinData::MultiValue
require ‘bindata’
A Struct is an ordered collection of named data objects.
- A list of the names of fields that are to be hidden
- Either :little or :big. This specifies the default
def _do_num_bytes(name)
by +name+. If +name+ is nil then returns the number of bytes required
Returns the number of bytes it will take to write the field represented
def _do_num_bytes(name) if name.nil? instantiate_all (@field_objs.inject(0) { |sum, f| sum + f.do_num_bytes }).ceil else obj = find_obj_for_name(name.to_s) obj.nil? ? 0 : obj.do_num_bytes end end
def _do_read(io)
def _do_read(io) instantiate_all @field_objs.each { |f| f.do_read(io) } end
def _do_write(io)
def _do_write(io) instantiate_all @field_objs.each { |f| f.do_write(io) } end
def _snapshot
def _snapshot hash = Snapshot.new field_names.each do |name| ss = find_obj_for_name(name).snapshot hash[name] = ss unless ss.nil? end hash end
def clear(name = nil)
Clears the field represented by +name+. If no +name+
def clear(name = nil) if name.nil? @field_objs.each { |f| f.clear unless f.nil? } else obj = find_obj_for_name(name.to_s) obj.clear unless obj.nil? end end
def clear?(name = nil)
Returns if the field represented by +name+ is clear?. If no +name+
def clear?(name = nil) if name.nil? @field_objs.each do |f| return false unless f.nil? or f.clear? end true else obj = find_obj_for_name(name.to_s) obj.nil? ? true : obj.clear? end end
def done_read
def done_read @field_objs.each { |f| f.done_read unless f.nil? } end
def field_names(include_hidden = false)
object. +include_hidden+ specifies whether to include hidden names
Returns a list of the names of all fields accessible through this
def field_names(include_hidden = false) # collect field names names = [] hidden = no_eval_param(:hide) @field_names.each do |name| if include_hidden or not hidden.include?(name) names << name end end names end
def find_obj_for_name(name)
def find_obj_for_name(name) idx = @field_names.index(name) if idx instantiate_obj(idx) @field_objs[idx].obj else nil end end
def inherited(subclass) #:nodoc:
### DEPRECATION HACK to warn about inheriting from BinData::Struct
def inherited(subclass) #:nodoc: if subclass != MultiValue # warn about deprecated method - remove before releasing 1.0 fail "error: inheriting from BinData::Struct has been deprecated. Inherit from BinData::MultiValue instead." end end
def initialize(params = {}, parent = nil)
def initialize(params = {}, parent = nil) super(params, parent) # extract field names but don't instantiate the fields @field_names = no_eval_param(:fields).collect { |k, n, p| n } @field_objs = [] end
def instantiate_all
def instantiate_all @field_names.each_with_index { |name, i| instantiate_obj(i) } end
def instantiate_obj(idx)
def instantiate_obj(idx) if @field_objs[idx].nil? fklass, fname, fparams = no_eval_param(:fields)[idx] @field_objs[idx] = fklass.new(fparams, self) end end
def method_missing(symbol, *args, &block)
def method_missing(symbol, *args, &block) name = symbol.id2name is_writer = (name[-1, 1] == "=") name.chomp!("=") # find the object that is responsible for name if (obj = find_obj_for_name(name)) # pass on the request if obj.single_value? and is_writer obj.value = *args elsif obj.single_value? obj.value else obj end else super end end
def offset_of(field)
def offset_of(field) idx = @field_names.index(field.to_s) if idx instantiate_all offset = 0 (0...idx).each do |i| this_offset = @field_objs[i].do_num_bytes if ::Float === offset and ::Integer === this_offset offset = offset.ceil end offset += this_offset end offset else nil end end
def respond_to?(symbol, include_private = false)
def respond_to?(symbol, include_private = false) orig_respond_to?(symbol, include_private) || field_names(true).include?(symbol.id2name.chomp("=")) end
def sanitize_parameters!(sanitizer, params)
def sanitize_parameters!(sanitizer, params) # possibly override endian endian = params[:endian] if endian != nil unless [:little, :big].include?(endian) raise ArgumentError, "unknown value for endian '#{endian}'" end params[:endian] = endian end if params.has_key?(:fields) sanitizer.with_endian(endian) do # ensure names of fields are strings and that params is sanitized all_fields = params[:fields].collect do |ftype, fname, fparams| fname = fname.to_s klass = sanitizer.lookup_klass(ftype) sanitized_fparams = sanitizer.sanitize_params(klass, fparams) [klass, fname, sanitized_fparams] end params[:fields] = all_fields end # now params are sanitized, check that parameter names are okay field_names = [] instance_methods = self.instance_methods reserved_names = RESERVED params[:fields].each do |fklass, fname, fparams| # check that name doesn't shadow an existing method if instance_methods.include?(fname) raise NameError.new("Rename field '#{fname}' in #{self}, " + "as it shadows an existing method.", fname) end # check that name isn't reserved if reserved_names.include?(fname) raise NameError.new("Rename field '#{fname}' in #{self}, " + "as it is a reserved name.", fname) end # check for multiple definitions if field_names.include?(fname) raise NameError.new("field '#{fname}' in #{self}, " + "is defined multiple times.", fname) end field_names << fname end # collect all hidden names that correspond to a field name hide = [] if params.has_key?(:hide) hidden = (params[:hide] || []).collect { |h| h.to_s } all_field_names = params[:fields].collect { |k,n,p| n } hide = hidden & all_field_names end params[:hide] = hide end super(sanitizer, params) end
def single_value?
Returns whether this data object contains a single value. Single
def single_value? return false end