class Arcana::Offset

Public Class Methods

new(str) click to toggle source
# File lib/arcana.rb, line 60
def initialize(str)
  @str = str
end

Public Instance Methods

exact?() click to toggle source
# File lib/arcana.rb, line 64
def exact?
  @str.match?(/\A(?:-?[0-9]+|0x[0-9a-fA-F]+)\z/)
end
indirect?() click to toggle source
# File lib/arcana.rb, line 68
def indirect?
  @str.start_with?("(")
end
position(input) click to toggle source
# File lib/arcana.rb, line 82
def position(input)
  if exact?
    Integer(@str)
  elsif indirect?
    @str.match(/\A\(([0-9]+|0x[0-9a-fA-F]+)([.,])([bBcCeEfFgGhHiIlLmsSqQ])([+-](?:[0-9]+|0x[0-9a-fA-F]+))?\)\z/) || return
    add = $4 ? Integer($4) : 0
    value = read_indirect(input, offset: Integer($1), signed: ($2 == ","), type: $3)
    return unless value # fixme
    value + add
  else
    binding.irb
  end
end
relative?() click to toggle source
# File lib/arcana.rb, line 72
def relative?
  @str.start_with?("&")
end
seek(input) click to toggle source
# File lib/arcana.rb, line 76
def seek(input)
  pos = position(input)
  return if pos.nil? # FIXME: raise?
  input.seek_pos(pos)
end
to_s() click to toggle source
# File lib/arcana.rb, line 96
def to_s
  @str
end

Private Instance Methods

read_indirect(input, offset:, type:, signed:) click to toggle source
# File lib/arcana.rb, line 102
def read_indirect(input, offset:, type:, signed:)
  input.seek_absolute(offset)
  return if input.eof? # FIXME

  case type
  when "b", "c", "B", "C"
    input.read(1).ord
  when "h", "s"
    input.read(2).unpack("s<")[0]
  when "H", "S"
    input.read(2).unpack("s>")[0]
  when "l"
    # also default?
    input.read(2).unpack("l<")[0]
  when "L"
    # also default?
    input.read(2).unpack("l>")[0]
  when "I"
    # https://stackoverflow.com/questions/5223025/why-do-mp3-files-use-synchsafe-integers
    bytes = input.read(4).bytes
    bytes[0] << 21 | bytes[1] << 14 | bytes[2] << 7 | bytes[3]
  else
    binding.irb
    raise "unsupported indirect type: #{type}"
  end
end