class Rasm::Java::Bytecode

ClassFile {

u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];

}

Attributes

attributes[R]
fields[R]
interfaces[R]
methods[R]
super_class[R]
version[R]

Public Class Methods

new(class_file) click to toggle source
# File lib/rasm/java/bytecode.rb, line 33
def initialize(class_file)
  open class_file, 'rb' do|io|
    magic = io.read(4).unpack('N')[0]
    if magic == 0xCAFEBABE
      @version = io.read(4).unpack('nn').reverse.join('.')
      pull_cp_info(io)
      self.access_flags, this_class, super_class, interfaces_count = io.read(8).unpack('n*')
      @interfaces = interfaces_count > 0 ? io.read(2 * interfaces_count).unpack('n*').map{|item| constant_pool[item].val} : []
      self.name, @super_class = constant_pool[this_class].val, constant_pool[super_class].val

      @fields = pull_list(io, FieldInfo)
      @methods = pull_list(io, MethodInfo)
      @attributes = pull_attributes(io)
    else
      raise "magic #{magic} is not valid java class file."
    end
  end
end

Public Instance Methods

constant_pool() click to toggle source
# File lib/rasm/java/bytecode.rb, line 78
def constant_pool
  @constant_pool ||= {}
end
cp_info() click to toggle source
# File lib/rasm/java/bytecode.rb, line 82
def cp_info
  str = "cp_info (#{@constant_pool_count}) \n"
  constant_pool.each do|i, e|
    if e.is_a? Ref
      str << "#%02d = %-16s %-20s %s\n" % [i, e.name, e, ("//#{e.val}" if e.is_a?(Ref))]
    else
      str << "#%02d = %-16s %-20s\n" % [i, e.name, e.val]
    end

  end
  str
end
to_s() click to toggle source
# File lib/rasm/java/bytecode.rb, line 52
def to_s
  access = access_flags
  str = ''
  if access & ACC_DEPRECATED != 0
    str << "//DEPRECATED\n"
  end
  str << "// access flags 0x%x\n" % access
  str << access_desc
  if (access & ACC_ANNOTATION) != 0
    str << '@interface '
  elsif (access & ACC_INTERFACE) != 0
    str << 'interface ';
  elsif (access & ACC_ENUM) == 0
    str << 'class '
  end
  str << name
  str << " extends #{super_class} " if super_class && super_class != 'java/lang/Object'
  str << " implements %s {\n" % interfaces.join(',') unless interfaces.empty?
  fields.each do|f|
    str << "#{f}\n"
  end
  str << "\n}"
  str
end

Private Instance Methods

pull_attributes(io) click to toggle source
# File lib/rasm/java/bytecode.rb, line 126
def pull_attributes(io)
  attributes_count = io.read(2).unpack('n')[0]
  attributes = []
  attributes_count.times do
    attribute_name_index, attribute_length = io.read(6).unpack('nN')
    name = constant_pool[attribute_name_index].val
    attributes << Attribute.of(constant_pool, name, io.read(attribute_length))
  end
  attributes
end
pull_cp_info(io) click to toggle source
# File lib/rasm/java/bytecode.rb, line 96
def pull_cp_info(io)
  @constant_pool_count = io.read(2).unpack('n')[0]
  i = 1
  while i < @constant_pool_count
    tag = io.read(1).unpack('C')[0]
    constant_type = CONSTANT_TYPES[tag]
    if constant_type
      target = constant_type.value_at(io)
      constant_pool[i] = target.respond_to?(:call) ? target.call(constant_pool) : target
    end
    i += 1 if tag == 5 || tag == 6
    i += 1
  end
end
pull_list(io, type) click to toggle source
# File lib/rasm/java/bytecode.rb, line 111
def pull_list(io, type)
  fields_count = io.read(2).unpack('n')[0]
  items = []
  if fields_count > 0
    fields_count.times do
      access_flags, name_index, descriptor_index = io.read(6).unpack('n*')
      attributes = pull_attributes(io)
      item = type.new(constant_pool[descriptor_index].val, attributes)
      item.access_flags, item.name = access_flags, constant_pool[name_index].val
      items << item
    end
  end
  items
end