class BinData::Base

adjust the IO offset instead of raising an error.
:check_offset, except that it will
position before reading. This is like
[:adjust_offset] Ensures that the current IO offset is at this
before reading.
this parameter. This parameter is only checked
is made available to any lambda assigned to
to the current offset. The variable offset
success or failure. Any other return is compared
meet this criteria. A boolean return indicates
[:check_offset] Raise an error if the current IO offset doesn’t
an object. These params are:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
This is the abstract base class for all data objects.

def ==(other)

def ==(other)
  # double dispatch
  other == snapshot
end

def _assign(val)

always be deep copied to ensure no aliasing problems can occur.
Assigns the value of +val+ to this data object. Note that +val+ will
def _assign(val)
  raise NotImplementedError
end

def _do_num_bytes(deprecated)

Returns the number of bytes it will take to write this data.
def _do_num_bytes(deprecated)
  raise NotImplementedError
end

def _do_read(io)

Reads the data for this data object from +io+.
def _do_read(io)
  raise NotImplementedError
end

def _do_write(io)

Writes the value for this data to +io+.
def _do_write(io)
  raise NotImplementedError
end

def _done_read

Trigger function that is called after #do_read.
def _done_read
  raise NotImplementedError
end

def _snapshot

Returns a snapshot of this data object.
def _snapshot
  raise NotImplementedError
end

def accepted_parameters

def accepted_parameters
  unless defined? @accepted_parameters
    ancestor = ancestors[1..-1].find { |cls|
                                  cls.respond_to?(:accepted_parameters)
                                 }
    ancestor_params = ancestor.nil? ? nil : ancestor.accepted_parameters
    @accepted_parameters = AcceptedParameters.new(ancestor_params)
  end
  @accepted_parameters
end

def adjust_offset(io)

def adjust_offset(io)
  actual_offset = io.offset
  expected = eval_parameter(:adjust_offset)
  if actual_offset != expected
    begin
      seek = expected - actual_offset
      io.seekbytes(seek)
      warn "adjusting stream position by #{seek} bytes" if $VERBOSE
    rescue
      raise ValidityError,
            "offset is '#{actual_offset}' but couldn't seek to " +
            "expected '#{expected}' for #{debug_name}"
    end
  end
end

def assign(val)

always be deep copied to ensure no aliasing problems can occur.
Assigns the value of +val+ to this data object. Note that +val+ will
def assign(val)
  _assign(val)
end

def check_offset(io)

def check_offset(io)
  actual_offset = io.offset
  expected = eval_parameter(:check_offset, :offset => actual_offset)
  if not expected
    raise ValidityError, "offset not as expected for #{debug_name}"
  elsif actual_offset != expected and expected != true
    raise ValidityError,
          "offset is '#{actual_offset}' but " +
          "expected '#{expected}' for #{debug_name}"
  end
end

def check_or_adjust_offset(io)

def check_or_adjust_offset(io)
  if has_parameter?(:check_offset)
    check_offset(io)
  elsif has_parameter?(:adjust_offset)
    adjust_offset(io)
  end
end

def clear

Resets the internal state to that of a newly created object.
def clear
  raise NotImplementedError
end

def clear?

Returns true if the object has not been changed since creation.
def clear?
  raise NotImplementedError
end

def debug_name

Returns a user friendly name of this object for debugging purposes.
def debug_name
  if parent
    parent.debug_name_of(self)
  else
    "obj"
  end
end

def debug_name_of(child)

by objects that contain child objects.
Returns the debug name of +child+. This only needs to be implemented
def debug_name_of(child)
  raise NotImplementedError
end

def default_parameters(*args)

def default_parameters(*args)
  accepted_parameters.default(*args)
end

def do_num_bytes(deprecated = nil)

def do_num_bytes(deprecated = nil)
  _do_num_bytes(deprecated)
end

def do_read(io)

def do_read(io)
  check_or_adjust_offset(io)
  clear
  _do_read(io)
end

def do_write(io)

def do_write(io)
  _do_write(io)
end

def done_read

def done_read
  _done_read
end

def eval_parameter(key, overrides = {})

Returns nil if +key+ does not refer to any parameter.
parameters given at object construction to be overridden.
+overrides+ is an optional +parameters+ like hash that allow the
Returns the result of evaluating the parameter identified by +key+.
def eval_parameter(key, overrides = {})
  LazyEvaluator.eval(self, get_parameter(key), overrides)
end

def get_parameter(key)

You most likely want #eval_parameter.
Use this method if you are sure the parameter is not to be evaluated.
Returns the parameter referenced by +key+.
def get_parameter(key)
  @params[key]
end

def has_parameter?(key)

Returns whether +key+ exists in the +parameters+ hash.
def has_parameter?(key)
  @params.has_parameter?(key)
end

def initialize(params = {}, parent = nil)

under.
parent data object (e.g. struct, array, choice) this object resides
reference callable objects (methods or procs). +parent+ is the
+params+ is a hash containing symbol keys. Some params may

Creates a new data object.
def initialize(params = {}, parent = nil)
  @params = Sanitizer.sanitize(params, self.class)
  @parent = parent
end

def inspect

Return a human readable representation of this data object.
def inspect
  snapshot.inspect
end

def mandatory_parameters(*args)

def mandatory_parameters(*args)
  accepted_parameters.mandatory(*args)
end

def mutually_exclusive_parameters(*args)

def mutually_exclusive_parameters(*args)
  accepted_parameters.mutually_exclusive(*args)
end

def num_bytes(deprecated = nil)

Returns the number of bytes it will take to write this data.
def num_bytes(deprecated = nil)
  num = do_num_bytes(deprecated)
  num.ceil
end

def offset

Returns the offset of this object wrt to its most distant ancestor.
def offset
  if parent
    parent.offset_of(self)
  else
    0
  end
end

def offset_of(child)

by objects that contain child objects.
Returns the offset of +child+. This only needs to be implemented
def offset_of(child)
  raise NotImplementedError
end

def optional_parameters(*args)

def optional_parameters(*args)
  accepted_parameters.optional(*args)
end

def read(io)

created data object.
Instantiates this class and reads from +io+, returning the newly
def read(io)
  data = self.new
  data.read(io)
  data
end

def read(io)

Reads data into this data object.
def read(io)
  io = BinData::IO.new(io) unless BinData::IO === io
  do_read(io)
  done_read
  self
end

def register(name, class_to_register)

def register(name, class_to_register)
  RegisteredClasses.register(name, class_to_register)
end

def sanitize_parameters!(params, sanitizer)

def sanitize_parameters!(params, sanitizer)
end

def single_value?

def single_value?
  warn "#single_value? is deprecated.  It should no longer be needed"
  false
end

def snapshot

Returns a snapshot of this data object.
def snapshot
  _snapshot
end

def to_binary_s

Returns the string representation of this data object.
def to_binary_s
  io = StringIO.new
  write(io)
  io.rewind
  io.read
end

def to_s

Return a string representing this data object.
def to_s
  snapshot.to_s
end

def warn_replacement_parameter(params, bad_key, suggested_key)

def warn_replacement_parameter(params, bad_key, suggested_key)
  if params.has_parameter?(bad_key)
    warn ":#{bad_key} is not used with #{self}.  " +
         "You probably want to change this to :#{suggested_key}"
  end
end

def write(io)

Writes the value for this data to +io+.
def write(io)
  io = BinData::IO.new(io) unless BinData::IO === io
  do_write(io)
  io.flush
  self
end