Class: JvmBytecode::ClassFile

Inherits:
Object
  • Object
show all
Includes:
AccessFlag
Defined in:
lib/jvm_bytecode/class_file.rb

Constant Summary collapse

MAGIC_NUMBER =
[0xCA, 0xFE, 0xBA, 0xBE].pack('C4').freeze
ACCESS_FLAGS =
{
  public: 0x0001,
  final: 0x0010,
  super: 0x0020,
  interface: 0x0200,
  abstract: 0x0400,
  synthetic: 0x1000,
  anotation: 0x2000,
  enum: 0x4000
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AccessFlag

#access_flag, #all_access_flag, #readable_access_flag, #set_access_flag

Constructor Details

#initialize(&block) ⇒ ClassFile

Returns a new instance of ClassFile.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/jvm_bytecode/class_file.rb', line 22

def initialize(&block)
  @cp = ConstantPool.new

  @minor_ver = 0
  @major_ver = 52

  @this_class = nil
  @super_class = nil

  @interfaces = []
  @fields = []
  @methods = []
  @attributes = []

  self.instance_eval(&block) if block_given?
end

Class Method Details

.decode(io) ⇒ Object



18
19
20
# File 'lib/jvm_bytecode/class_file.rb', line 18

def self.decode(io)
  new.tap { |cf| cf.decode(io) }
end

Instance Method Details

#add_method(m) ⇒ Object



63
64
65
# File 'lib/jvm_bytecode/class_file.rb', line 63

def add_method(m)
  @methods.push(m).last
end

#bytecodeObject



77
78
79
80
81
82
83
84
85
86
# File 'lib/jvm_bytecode/class_file.rb', line 77

def bytecode
  version    = [@minor_ver, @major_ver].pack('S>*')
  classes    = [access_flag, @this_class, @super_class].pack('S>*')
  interfaces = ([@interfaces.length] + @interfaces).pack("S>*")
  fields     = @fields.join_bytecodes
  methods    = @methods.join_bytecodes
  attributes = @attributes.join_bytecodes

  MAGIC_NUMBER + version + @cp.bytecode + classes + interfaces + fields + methods + attributes
end

#constant_pool(&block) ⇒ Object



39
40
41
# File 'lib/jvm_bytecode/class_file.rb', line 39

def constant_pool(&block)
  @cp.tap { |cp| cp.instance_eval(&block) if block_given? }
end

#decode(io) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/jvm_bytecode/class_file.rb', line 88

def decode(io)
  raise Errors::DecodeError, 'Not class file' if io.read(4) != MAGIC_NUMBER

  @minor_ver, @major_ver = io.read(4).unpack('S>2')

  @cp.decode(io)

  acc_flag, @this_class, @super_class = io.read(6).unpack('S>3')
  set_access_flag(acc_flag)

  if_count = io.read(2).unpack('S>').first
  @interfaces = io.read(if_count * 2).unpack("S>#{if_count}")

  @fields = Field.decode_serial(@cp, io)
  @methods = Method.decode_serial(@cp, io)
end

#major_version(v) ⇒ Object



47
48
49
# File 'lib/jvm_bytecode/class_file.rb', line 47

def major_version(v)
  @major_ver = v
end

#method_definition(&block) ⇒ Object



67
68
69
# File 'lib/jvm_bytecode/class_file.rb', line 67

def method_definition(&block)
  add_method(new_method).tap { |m| m.instance_eval(&block) if block_given?}
end

#minor_version(v) ⇒ Object



43
44
45
# File 'lib/jvm_bytecode/class_file.rb', line 43

def minor_version(v)
  @minor_ver = v
end

#new_methodObject



59
60
61
# File 'lib/jvm_bytecode/class_file.rb', line 59

def new_method
  Method.new(@cp)
end

#source_file(filename) ⇒ Object



71
72
73
74
75
# File 'lib/jvm_bytecode/class_file.rb', line 71

def source_file(filename)
  @attributes << Attributes::SourceFile.new(@cp).tap do |a|
    a.filename(filename)
  end
end

#super_class(name) ⇒ Object



55
56
57
# File 'lib/jvm_bytecode/class_file.rb', line 55

def super_class(name)
  @super_class = @cp.class_index(name)
end

#this_class(name) ⇒ Object



51
52
53
# File 'lib/jvm_bytecode/class_file.rb', line 51

def this_class(name)
  @this_class = @cp.class_index(name)
end

#to_hashObject



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/jvm_bytecode/class_file.rb', line 105

def to_hash
  {
    minor_version: @minor_ver,
    major_version: @major_ver,
    constant_pool: @cp.to_hash,
    access_flag: readable_access_flag,
    this_class: @this_class,
    super_class: @super_class,
    methods: @methods.map(&:to_hash)
  }
end