javaclass 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +51 -0
- data/Readme.txt +47 -0
- data/history.txt +29 -0
- data/lib/javaclass/access_flags.rb +44 -0
- data/lib/javaclass/class_magic.rb +27 -0
- data/lib/javaclass/class_version.rb +65 -0
- data/lib/javaclass/constant_pool.rb +85 -0
- data/lib/javaclass/constants/base.rb +31 -0
- data/lib/javaclass/constants/double_reference.rb +81 -0
- data/lib/javaclass/constants/single_reference.rb +58 -0
- data/lib/javaclass/constants/value.rb +114 -0
- data/lib/javaclass/java_class_header.rb +88 -0
- data/lib/javaclass/references.rb +31 -0
- data/lib/javaclass/string_ux.rb +39 -0
- data/lib/javaclass.rb +14 -0
- data/test/data/AccessFlagsTestAbstract.class +0 -0
- data/test/data/AccessFlagsTestAbstract.java +3 -0
- data/test/data/AccessFlagsTestFinal.class +0 -0
- data/test/data/AccessFlagsTestFinal.java +3 -0
- data/test/data/AccessFlagsTestInterface.class +0 -0
- data/test/data/AccessFlagsTestInterface.java +3 -0
- data/test/data/AccessFlagsTestPackage.class +0 -0
- data/test/data/AccessFlagsTestPackage.java +3 -0
- data/test/data/AccessFlagsTestPublic$InnerClass.class +0 -0
- data/test/data/AccessFlagsTestPublic.class +0 -0
- data/test/data/AccessFlagsTestPublic.java +7 -0
- data/test/data/ClassVersionTest.java +1 -0
- data/test/data/ClassVersionTest10.class +0 -0
- data/test/data/ClassVersionTest11.class +0 -0
- data/test/data/ClassVersionTest12.class +0 -0
- data/test/data/ClassVersionTest13.class +0 -0
- data/test/data/ClassVersionTest14.class +0 -0
- data/test/data/ClassVersionTest15.class +0 -0
- data/test/data/ClassVersionTest16.class +0 -0
- data/test/data/ConstantPoolTest.class +0 -0
- data/test/data/ConstantPoolTest.java +20 -0
- data/test/data/makeAccessFlagsTest.bat +9 -0
- data/test/data/makeClassVersionTest.bat +35 -0
- data/test/data/makeConstantPoolTest.bat +6 -0
- data/test/setup.rb +14 -0
- data/test/test_access_flags.rb +53 -0
- data/test/test_base.rb +22 -0
- data/test/test_class_version.rb +59 -0
- data/test/test_constant_pool.rb +90 -0
- data/test/test_java_class_header.rb +30 -0
- data/test/test_references.rb +29 -0
- data/test/test_string_ux.rb +30 -0
- data/test/ts_all_tests.rb +36 -0
- metadata +106 -0
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
|
9
|
+
jcversion = '0.0.2'
|
10
|
+
|
11
|
+
gemspec = Gem::Specification.new do |s|
|
12
|
+
s.name = 'javaclass'
|
13
|
+
s.version = jcversion
|
14
|
+
s.summary ='A parser and disassembler for Java class files'
|
15
|
+
s.files = FileList['Readme.txt', '{lib,test}/**/*.*', 'history.txt', 'Rakefile']
|
16
|
+
s.test_files = FileList["{test}/**/test_*.rb"]
|
17
|
+
s.require_path = 'lib'
|
18
|
+
s.has_rdoc = true
|
19
|
+
s.rubyforge_project = 'javaclass'
|
20
|
+
s.homepage = 'http://javaclass.rubyforge.org/'
|
21
|
+
s.author = 'Peter Kofler'
|
22
|
+
s.email = 'bruno41 at rubyforge dot org'
|
23
|
+
# TODO use new cc email
|
24
|
+
s.platform = Gem::Platform::RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
28
|
+
pkg.need_zip = true
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::PackageTask.new(gemspec.name, gemspec.version) do |pkg|
|
32
|
+
#pkg.need_tar = true - no compress in tar on unxutils in Windows
|
33
|
+
#pkg.need_tar_gz = true - no compress in tar on unxutils in Windows
|
34
|
+
pkg.need_zip = true
|
35
|
+
pkg.package_files.include gemspec.files
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::TestTask.new do |t|
|
39
|
+
t.pattern = 'test/**/test_*.rb'
|
40
|
+
t.warning = true
|
41
|
+
t.verbose = false
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
# rdoc.rdoc_dir = 'html'
|
46
|
+
rdoc.title = "JavaClass javaclass-#{jcversion} Documentation"
|
47
|
+
rdoc.main = 'Readme.txt'
|
48
|
+
rdoc.rdoc_files.include 'Readme.txt', 'lib/**/*.rb', 'history.txt'
|
49
|
+
end
|
50
|
+
|
51
|
+
task :default => :test
|
data/Readme.txt
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
JavaClass
|
2
|
+
by {Peter Kofler}[http://kofler.dot.at/work/]
|
3
|
+
|
4
|
+
* {Homepage}[http://javaclass.rubyforge.org/]
|
5
|
+
* {Rubyforge Project}[http://rubyforge.org/projects/javaclass]
|
6
|
+
* email bruno41 at rubyforge dot org
|
7
|
+
|
8
|
+
== Description
|
9
|
+
|
10
|
+
JavaClass (Java Class File Parser) is a
|
11
|
+
parser and disassembler for Java class files, similar to the javap command.
|
12
|
+
It provides access to the package, protected, and public fields and methods
|
13
|
+
of the classes passed to it together with a list of all outgoing references.
|
14
|
+
|
15
|
+
== Motivation
|
16
|
+
|
17
|
+
I am still doing Java most of the time. I used to be quite enthusiatic about
|
18
|
+
it, but after 9 years I can see the advantages of being a polyglot. So I use
|
19
|
+
Ruby for all kind of stuff, just for fun. Recently I needed some Java class
|
20
|
+
analysis and happened to write it with Ruby. As I am a puritan, I did not
|
21
|
+
want to call javap from my script, so I started disassembling the class files,
|
22
|
+
which might be the the base for some serious static code analysis tools. (I
|
23
|
+
started adding methods to that end...)
|
24
|
+
|
25
|
+
== Install
|
26
|
+
|
27
|
+
sudo gem install javaclass
|
28
|
+
|
29
|
+
== Usage
|
30
|
+
|
31
|
+
require 'javaclass'
|
32
|
+
|
33
|
+
clazz = JavaClass.parse('packagename/Public.class')
|
34
|
+
clazz.version # => 50.0
|
35
|
+
clazz.constant_pool.items[1] # => packagename/Public
|
36
|
+
clazz.access_flags.public? # => true
|
37
|
+
clazz.this_class # => packagename/Public
|
38
|
+
clazz.super_class # => java/lang/Object
|
39
|
+
clazz.references.referenced_methods[0] # => java/lang/Object.<init>:()V
|
40
|
+
|
41
|
+
== Requirements
|
42
|
+
|
43
|
+
JavaClass does not depend on any other installed libraries or gems.
|
44
|
+
|
45
|
+
== License
|
46
|
+
|
47
|
+
Same as Ruby.
|
data/history.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
=== 0.0.2 08/04/2009
|
2
|
+
|
3
|
+
* refactored code to smaller objects for version and constant pool
|
4
|
+
* fixed float and double constant pool items
|
5
|
+
* added tests
|
6
|
+
* continued implementation with class names and references
|
7
|
+
|
8
|
+
=== 0.0.1 01/03/2009
|
9
|
+
|
10
|
+
* initial version extracted from ClassList project
|
11
|
+
* reads the class version and package/public flag of a class
|
12
|
+
* understands the constant pool but does not use it
|
13
|
+
|
14
|
+
=== Planned
|
15
|
+
|
16
|
+
* continue function for fields and methods
|
17
|
+
* implement
|
18
|
+
* dump to return the class same as javap
|
19
|
+
* isAnnotation (checks version>=5 & superclass)
|
20
|
+
* are Annotation extendable, if so how do they look? (javap)
|
21
|
+
* isEnum (checks version>=5 & superclass)
|
22
|
+
* are Enums extendable (yes), if so how do they look? (javap)
|
23
|
+
* test
|
24
|
+
* test with all classes of all JDKs against javap from this version
|
25
|
+
* Java 1.0 - private protected fields.
|
26
|
+
* Java 1.0 - http://www.javaworld.com/javaworld/javaqa/1999-06/03-synchronized.html
|
27
|
+
* think about
|
28
|
+
* "metric" if all referencing classes of a class is another package, propose moving it there.
|
29
|
+
* add zip gem to load classes directly from the classpath (i.e. the jars), add gem dependency
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'javaclass/string_ux'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
|
5
|
+
# The access flags of a class or interface.
|
6
|
+
# Author:: Peter Kofler
|
7
|
+
class AccessFlags
|
8
|
+
|
9
|
+
# Access flags as defined by JVM spec.
|
10
|
+
ACC_PUBLIC = 0x0001
|
11
|
+
ACC_FINAL = 0x0010
|
12
|
+
ACC_SUPER = 0x0020 # old invokespecial instruction semantics
|
13
|
+
ACC_INTERFACE = 0x0200
|
14
|
+
ACC_ABSTRACT = 0x0400
|
15
|
+
ACC_OTHER = 0xffff ^ ACC_PUBLIC ^ ACC_FINAL ^ ACC_SUPER ^ ACC_INTERFACE ^ ACC_ABSTRACT
|
16
|
+
|
17
|
+
def initialize(data, pos)
|
18
|
+
@flags = data.u2(pos)
|
19
|
+
raise "inconsistent flags #{flags}" if abstract? && final?
|
20
|
+
raise "inconsistent flags #{flags}" if interface? && (!abstract? || final?)
|
21
|
+
raise "inconsistent flags #{flags}" if (@flags & ACC_OTHER) != 0
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return +true+ if the class is public.
|
25
|
+
def public?
|
26
|
+
(@flags & ACC_PUBLIC) != 0
|
27
|
+
end
|
28
|
+
alias accessible? public?
|
29
|
+
|
30
|
+
def final?
|
31
|
+
(@flags & ACC_FINAL) != 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def abstract?
|
35
|
+
(@flags & ACC_ABSTRACT) != 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def interface?
|
39
|
+
(@flags & ACC_INTERFACE) != 0
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module JavaClass
|
2
|
+
|
3
|
+
# The +CAFEBABE+ magic of a class file.
|
4
|
+
# Author:: Peter Kofler
|
5
|
+
class ClassMagic
|
6
|
+
|
7
|
+
CAFE_BABE = "\xCA\xFE\xBA\xBE"
|
8
|
+
|
9
|
+
# Check the class magic in the _data_ beginning at position _start_ (which is usually 0).
|
10
|
+
def initialize(data, start=0)
|
11
|
+
# "parsing"
|
12
|
+
@bytes = data[start..start+3]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return +true+ if the data was valid, i.e. if the class started with +CAFEBABE+.
|
16
|
+
def valid?
|
17
|
+
@bytes == CAFE_BABE
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return the value of the magic in this class.
|
21
|
+
def bytes
|
22
|
+
@bytes.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'javaclass/string_ux'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
|
5
|
+
# Version of a class file.
|
6
|
+
# Author:: Peter Kofler
|
7
|
+
# See:: http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#75883
|
8
|
+
class ClassVersion
|
9
|
+
|
10
|
+
attr_reader :minor
|
11
|
+
attr_reader :major
|
12
|
+
|
13
|
+
# Extract the class version from the bytes _data_ starting at position _start_ (which is usually 4).
|
14
|
+
def initialize(data, start=4)
|
15
|
+
# parsing
|
16
|
+
@minor = data.u2(start)
|
17
|
+
@major = data.u2(start+2)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return the class file version as +major+.+minor+ string like 48.0 (Java 1.4) or 50.0 (Java 6).
|
21
|
+
def to_s
|
22
|
+
"#{@major}.#{@minor}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the version as +major+.+minor+ float.
|
26
|
+
def to_f
|
27
|
+
if @minor <= 0
|
28
|
+
denom = 1.0
|
29
|
+
else
|
30
|
+
denom = 1.0 * 10**(Math.log10(@minor).floor + 1)
|
31
|
+
end
|
32
|
+
|
33
|
+
@major + @minor/denom
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return a debug output of this version.
|
37
|
+
def dump
|
38
|
+
[" minor version: #{@minor}", " major version: #{@major}"]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return the JDK version corresponding to this version like "1.6" or "unknown" if none matched.
|
42
|
+
def jdk_version
|
43
|
+
v = to_f
|
44
|
+
if v >= 45.0 && v <= 45.3 # 1.0.2 supports class file format versions 45.0 through 45.3 inclusive.
|
45
|
+
'1.0'
|
46
|
+
elsif v > 45.3 && v <= 45.65535 # 1.1.X can support class file formats of versions in the range 45.0 through 45.65535 inclusive
|
47
|
+
'1.1'
|
48
|
+
elsif v == 46.0 # JDK 1.2=46
|
49
|
+
'1.2'
|
50
|
+
elsif v == 47.0 # JDK 1.3=47
|
51
|
+
'1.3'
|
52
|
+
elsif v == 48.0 # JDK 1.4=48
|
53
|
+
'1.4'
|
54
|
+
elsif v == 49.0 # J2SE 5.0=49
|
55
|
+
'1.5'
|
56
|
+
elsif v == 50.0 # J2SE 6.0=50
|
57
|
+
'1.6'
|
58
|
+
else
|
59
|
+
'unknown'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'javaclass/string_ux'
|
2
|
+
require 'javaclass/constants/value'
|
3
|
+
require 'javaclass/constants/single_reference'
|
4
|
+
require 'javaclass/constants/double_reference'
|
5
|
+
|
6
|
+
module JavaClass
|
7
|
+
|
8
|
+
# Container of the constant pool's constants.
|
9
|
+
# Author:: Peter Kofler
|
10
|
+
class ConstantPool
|
11
|
+
|
12
|
+
# Types of constants by their +tag+.
|
13
|
+
CONSTANT_TYPE_TAGS = {
|
14
|
+
CLASS_TAG = 7 => Constants::ConstantClass,
|
15
|
+
FIELD_TAG = 9 => Constants::ConstantField,
|
16
|
+
METHOD_TAG = 10 => Constants::ConstantMethod,
|
17
|
+
INTERFACE_METHOD_TAG = 11 => Constants::ConstantInterfaceMethod,
|
18
|
+
STRING_TAG = 8 => Constants::ConstantString,
|
19
|
+
INT_TAG = 3 => Constants::ConstantInt,
|
20
|
+
FLOAT_TAG = 4 => Constants::ConstantFloat,
|
21
|
+
LONG_TAG = 5 => Constants::ConstantLong,
|
22
|
+
DOUBLE_TAG = 6 => Constants::ConstantDouble,
|
23
|
+
NAME_AND_TYPE_TAG = 12 => Constants::ConstantNameAndType,
|
24
|
+
ASCIZ_TAG = 1 => Constants::ConstantAsciz,
|
25
|
+
}
|
26
|
+
|
27
|
+
# Size of the whole constant pool in bytes.
|
28
|
+
attr_reader :size
|
29
|
+
|
30
|
+
# Parse the constant pool from the bytes _data_ beginning at position _start_ (which is usually 8).
|
31
|
+
def initialize(data, start=8)
|
32
|
+
@pool = {} # cnt (fixnum) => constant
|
33
|
+
|
34
|
+
# parsing
|
35
|
+
@item_count = data.u2(start)
|
36
|
+
pos = start + 2
|
37
|
+
cnt = 1
|
38
|
+
while cnt <= @item_count-1
|
39
|
+
|
40
|
+
type = CONSTANT_TYPE_TAGS[data.u1(pos)]
|
41
|
+
unless type
|
42
|
+
#puts dump.join("\n")
|
43
|
+
raise "const ##{cnt} = unknown constant pool tag #{data[pos]} at pos #{pos} in class"
|
44
|
+
end
|
45
|
+
|
46
|
+
constant = type.new(@pool, data, pos)
|
47
|
+
@pool[cnt] = constant
|
48
|
+
pos += constant.size
|
49
|
+
cnt += constant.slots
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
@size = pos - start
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return the number of pool items. This number might be larger than +items+ available,
|
57
|
+
# because +long+ and +double+ constants take two slots.
|
58
|
+
def item_count
|
59
|
+
@item_count-1
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return the _index_'th pool item. _index_ is the real index in the pool which may skip numbers.
|
63
|
+
def[](index)
|
64
|
+
@pool[index]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return an array of the ordered list of constants.
|
68
|
+
def items
|
69
|
+
@pool.keys.sort.collect { |k| self[k] }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return an array of all constants of the given _tags_ types.
|
73
|
+
def find(*tags)
|
74
|
+
items.find_all { |item| tags.include? item.tag }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return a debug output of the whole pool.
|
78
|
+
def dump
|
79
|
+
[" Constant pool:"] + @pool.keys.sort.collect { |k| "const ##{k} = #{self[k].dump}"}
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'javaclass/string_ux'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Constants # :nodoc:
|
5
|
+
|
6
|
+
# Superclass of constant values in the constant pool. Every constant has a +name+, a +tag+ and a +size+ in bytes.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class Base
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
attr_reader :tag
|
12
|
+
attr_reader :size
|
13
|
+
attr_reader :slots
|
14
|
+
|
15
|
+
# Set default constants.
|
16
|
+
def initialize(name=nil)
|
17
|
+
@name = self.class.to_s[/::[^:]+$/][10..-1] # skip modules (::) and "Constant"
|
18
|
+
@name = name if name
|
19
|
+
@size = 3
|
20
|
+
@slots = 1
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return part of debug output.
|
24
|
+
def dump
|
25
|
+
"#{@name}\t" # #{@tag}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'javaclass/constants/single_reference'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Constants # :nodoc:
|
5
|
+
|
6
|
+
# Superclass of double reference constants like +ConstantField+ (+FieldRef+) in the constant pool.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class DoubleReference < SingleReference
|
9
|
+
|
10
|
+
attr_reader :second_index
|
11
|
+
|
12
|
+
# Define a double reference into _pool_ from _data_ beginning at _start_
|
13
|
+
def initialize(pool, data, start, name=nil)
|
14
|
+
super(pool, data, start, name)
|
15
|
+
@size = 5
|
16
|
+
|
17
|
+
@second_index = data.u2(start+3)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return the second value, which is the referenced value from the pool.
|
21
|
+
def second_value
|
22
|
+
get(@second_index)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the value, which are both referenced values from the pool.
|
26
|
+
def to_s
|
27
|
+
"#{super}.#{second_value}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return part of debug output.
|
31
|
+
def dump
|
32
|
+
"#{@name}\t##{@first_index}.##{@second_index};\t// #{to_s}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class ConstantField < DoubleReference
|
38
|
+
alias class_index first_index
|
39
|
+
alias name_and_type_index second_index
|
40
|
+
def initialize(pool, data, start)
|
41
|
+
super(pool, data, start)
|
42
|
+
end
|
43
|
+
alias class_name first_value
|
44
|
+
end
|
45
|
+
|
46
|
+
class ConstantMethod < DoubleReference
|
47
|
+
alias class_index first_index
|
48
|
+
alias name_and_type_index second_index
|
49
|
+
def initialize(pool, data, start)
|
50
|
+
super(pool, data, start)
|
51
|
+
end
|
52
|
+
alias class_name first_value
|
53
|
+
end
|
54
|
+
|
55
|
+
class ConstantInterfaceMethod < DoubleReference
|
56
|
+
alias class_index first_index
|
57
|
+
alias name_and_type_index second_index
|
58
|
+
def initialize(pool, data, start)
|
59
|
+
super(pool, data, start)
|
60
|
+
end
|
61
|
+
alias class_name first_value
|
62
|
+
end
|
63
|
+
|
64
|
+
class ConstantNameAndType < DoubleReference
|
65
|
+
alias name_index first_index
|
66
|
+
alias descriptor_index second_index
|
67
|
+
def initialize(pool, data, start)
|
68
|
+
super(pool, data, start)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
"#{get(name_index)}:#{get(descriptor_index)}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def dump
|
76
|
+
"#{@name}\t##{name_index}:##{descriptor_index};// #{to_s}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'javaclass/constants/base'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Constants # :nodoc:
|
5
|
+
|
6
|
+
# Superclass of single reference constants like +ConstantClass+ (+Class+) in the constant pool.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class SingleReference < Base
|
9
|
+
|
10
|
+
attr_reader :first_index
|
11
|
+
|
12
|
+
# Define a single reference into _pool_ from _data_ beginning at _start_
|
13
|
+
def initialize(pool, data, start, name=nil)
|
14
|
+
super(name)
|
15
|
+
@tag = data.u1(start)
|
16
|
+
|
17
|
+
@enclosing_pool = pool
|
18
|
+
@first_index = data.u2(start+1)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return the value, which is the referenced value from the pool.
|
22
|
+
def first_value
|
23
|
+
get(@first_index)
|
24
|
+
end
|
25
|
+
alias to_s first_value
|
26
|
+
|
27
|
+
# Return part of debug output.
|
28
|
+
def dump
|
29
|
+
super + "##{@first_index};\t// #{to_s}"
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
# Get a reference _ref_ from the +enclosing_pool+
|
35
|
+
def get(ref)
|
36
|
+
@enclosing_pool[ref].to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class ConstantClass < SingleReference
|
42
|
+
alias name_index first_index
|
43
|
+
def initialize(pool, data, start)
|
44
|
+
super(pool, data, start, "class")
|
45
|
+
end
|
46
|
+
alias class_name first_value
|
47
|
+
end
|
48
|
+
|
49
|
+
class ConstantString < SingleReference
|
50
|
+
alias string_index first_index
|
51
|
+
def initialize(pool, data, start)
|
52
|
+
super(pool, data, start)
|
53
|
+
end
|
54
|
+
alias string_value first_value
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'javaclass/constants/base'
|
2
|
+
|
3
|
+
module JavaClass
|
4
|
+
module Constants # :nodoc:
|
5
|
+
|
6
|
+
# Superclass of value constants like +ConstantInt+ (+Integer+) in the constant pool.
|
7
|
+
# Author:: Peter Kofler
|
8
|
+
class Value < Base
|
9
|
+
|
10
|
+
attr_reader :value
|
11
|
+
|
12
|
+
# Create a constant value with an optional downcase _name_
|
13
|
+
def initialize(name=self.class.to_s[/::[^:]+$/][10..-1].downcase)
|
14
|
+
super(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the value as string.
|
18
|
+
def to_s
|
19
|
+
@value.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return part of debug output.
|
23
|
+
def dump
|
24
|
+
super + "#{@value}"
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# Define a +value+ from _data_ beginning at position _start_ with the _size_ in bytes and _slots_ (1 or 2).
|
30
|
+
def get_value(data, start, size, slots=1)
|
31
|
+
@tag = data.u1(start)
|
32
|
+
@size = size
|
33
|
+
@slots = slots
|
34
|
+
|
35
|
+
data[start+1..start+size-1]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Dummy method to "fix" unused warning of param _pool_ in Eclipse.
|
39
|
+
def silence_unused_warning(pool)
|
40
|
+
raise "pool is nil" unless pool
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class ConstantInt < Value
|
46
|
+
def initialize(pool, data, start)
|
47
|
+
super()
|
48
|
+
silence_unused_warning(pool)
|
49
|
+
@value = get_value(data, start, 5).u4
|
50
|
+
end
|
51
|
+
|
52
|
+
def dump
|
53
|
+
super + ';'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ConstantFloat < Value
|
58
|
+
def initialize(pool, data, start)
|
59
|
+
super()
|
60
|
+
silence_unused_warning(pool)
|
61
|
+
@value = get_value(data, start, 5).single
|
62
|
+
end
|
63
|
+
def to_s
|
64
|
+
super.upcase # sprintf('%E',@value)
|
65
|
+
end
|
66
|
+
def dump
|
67
|
+
super + 'f;'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class ConstantLong < Value
|
72
|
+
def initialize(pool, data, start)
|
73
|
+
super()
|
74
|
+
silence_unused_warning(pool)
|
75
|
+
@value = get_value(data, start, 9, 2).u8
|
76
|
+
end
|
77
|
+
def dump
|
78
|
+
super + 'l;'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class ConstantDouble < Value
|
83
|
+
def initialize(pool, data, start)
|
84
|
+
super()
|
85
|
+
silence_unused_warning(pool)
|
86
|
+
@value = get_value(data, start, 9, 2).double
|
87
|
+
end
|
88
|
+
def to_s
|
89
|
+
@value.to_s.upcase # sprintf('%E',@value)
|
90
|
+
end
|
91
|
+
def dump
|
92
|
+
super + 'd;'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ConstantAsciz < Value
|
97
|
+
alias string value
|
98
|
+
def initialize(pool, data, start)
|
99
|
+
super('Asciz')
|
100
|
+
silence_unused_warning(pool)
|
101
|
+
@tag = data.u1(start)
|
102
|
+
|
103
|
+
@length = data.u2(start+1)
|
104
|
+
@size = 3 + @length
|
105
|
+
@value = data[start+3..start+3+@length-1]
|
106
|
+
end
|
107
|
+
|
108
|
+
def dump
|
109
|
+
super + ';'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|