module BinData::CheckOrAdjustOffsetMixin

def self.included(base) #:nodoc:

:nodoc:
def self.included(base) #:nodoc:
  base.optional_parameters :check_offset, :adjust_offset
  base.mutually_exclusive_parameters :check_offset, :adjust_offset
end

def add_methods_for_check_or_adjust_offset

as appropriate.
Monkey patches #do_read to check or adjust the stream offset

To be called from BinData::Base#initialize.
def add_methods_for_check_or_adjust_offset
  if has_parameter?(:check_offset)
    class << self
      alias_method :do_read_without_check_offset, :do_read
      alias_method :do_read, :do_read_with_check_offset
    end
  end
  if has_parameter?(:adjust_offset)
    class << self
      alias_method :do_read_without_adjust_offset, :do_read
      alias_method :do_read, :do_read_with_adjust_offset
    end
  end
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 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 do_read_with_adjust_offset(io) #:nodoc:

:nodoc:
def do_read_with_adjust_offset(io) #:nodoc:
  adjust_offset(io)
  do_read_without_adjust_offset(io)
end

def do_read_with_check_offset(io) #:nodoc:

:nodoc:
def do_read_with_check_offset(io) #:nodoc:
  check_offset(io)
  do_read_without_check_offset(io)
end