javaclass 0.0.2 → 0.0.3
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 +208 -23
- data/Readme.txt +56 -19
- data/examples/generate_class_lists.rb +61 -0
- data/history.txt +13 -19
- data/lib/javaclass/classfile/access_flags.rb +52 -0
- data/lib/javaclass/classfile/class_magic.rb +29 -0
- data/lib/javaclass/classfile/class_version.rb +67 -0
- data/lib/javaclass/classfile/constant_pool.rb +91 -0
- data/lib/javaclass/classfile/constants/base.rb +33 -0
- data/lib/javaclass/classfile/constants/double_reference.rb +99 -0
- data/lib/javaclass/classfile/constants/single_reference.rb +65 -0
- data/lib/javaclass/classfile/constants/value.rb +116 -0
- data/lib/javaclass/classfile/java_class_header.rb +102 -0
- data/lib/javaclass/classfile/references.rb +43 -0
- data/lib/javaclass/classlist/class_entry.rb +89 -0
- data/lib/javaclass/classlist/jar_searcher.rb +69 -0
- data/lib/javaclass/classlist/list.rb +126 -0
- data/lib/javaclass/classlist/package_entry.rb +87 -0
- data/lib/javaclass/classpath/classpaths.txt +2 -0
- data/lib/javaclass/classpath/composite_classpath.rb +99 -0
- data/lib/javaclass/classpath/folder_classpath.rb +83 -0
- data/lib/javaclass/classpath/jar_classpath.rb +100 -0
- data/lib/javaclass/classpath/java_home_classpath.rb +40 -0
- data/lib/javaclass/classpath/port_ClassPathEntry.java +202 -0
- data/lib/javaclass/classpath/port_ClassPathEntryFactory.java +311 -0
- data/lib/javaclass/classpath/port_DirectoryRepository.java +24 -0
- data/lib/javaclass/java_name.rb +90 -0
- data/lib/javaclass/metric/ccd.rb +68 -0
- data/lib/javaclass/metric/class_usage.rb +41 -0
- data/lib/javaclass/metric/metrics.txt +15 -0
- data/lib/javaclass.rb +44 -11
- data/test/data/ShortClientData$1-4000Wert.class +0 -0
- data/test/data/{AccessFlagsTestAbstract.class → access_flags/AccessFlagsTestAbstract.class} +0 -0
- data/test/data/{AccessFlagsTestAbstract.java → access_flags/AccessFlagsTestAbstract.java} +0 -0
- data/test/data/{AccessFlagsTestFinal.class → access_flags/AccessFlagsTestFinal.class} +0 -0
- data/test/data/{AccessFlagsTestFinal.java → access_flags/AccessFlagsTestFinal.java} +0 -0
- data/test/data/{AccessFlagsTestInterface.class → access_flags/AccessFlagsTestInterface.class} +0 -0
- data/test/data/{AccessFlagsTestInterface.java → access_flags/AccessFlagsTestInterface.java} +0 -0
- data/test/data/{AccessFlagsTestPackage.class → access_flags/AccessFlagsTestPackage.class} +0 -0
- data/test/data/{AccessFlagsTestPackage.java → access_flags/AccessFlagsTestPackage.java} +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$Inner.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$InnerInterface.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic$StaticInner.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic.class +0 -0
- data/test/data/access_flags/AccessFlagsTestPublic.java +11 -0
- data/test/data/access_flags/AccessFlagsTestPublic_javap.txt +29 -0
- data/test/data/{makeAccessFlagsTest.bat → access_flags/make.bat} +0 -0
- data/test/data/{ClassVersionTest.java → class_version/ClassVersionTest.java} +0 -0
- data/test/data/{ClassVersionTest10.class → class_version/ClassVersionTest10.class} +0 -0
- data/test/data/{ClassVersionTest11.class → class_version/ClassVersionTest11.class} +0 -0
- data/test/data/{ClassVersionTest12.class → class_version/ClassVersionTest12.class} +0 -0
- data/test/data/{ClassVersionTest13.class → class_version/ClassVersionTest13.class} +0 -0
- data/test/data/{ClassVersionTest14.class → class_version/ClassVersionTest14.class} +0 -0
- data/test/data/{ClassVersionTest15.class → class_version/ClassVersionTest15.class} +0 -0
- data/test/data/{ClassVersionTest16.class → class_version/ClassVersionTest16.class} +0 -0
- data/test/data/{makeClassVersionTest.bat → class_version/make.bat} +0 -0
- data/test/data/{ConstantPoolTest.class → constant_pool/ConstantPoolTest.class} +0 -0
- data/test/data/{ConstantPoolTest.java → constant_pool/ConstantPoolTest.java} +0 -0
- data/test/data/{makeConstantPoolTest.bat → constant_pool/make.bat} +0 -0
- data/test/data/folder_classpath/JarClasspathTestFolder/ClassVersionTest10.class +0 -0
- data/test/data/folder_classpath/JarClasspathTestFolder/package/ClassVersionTest11.class +0 -0
- data/test/data/jar_classpath/JarClasspathTest.jar +0 -0
- data/test/data/jar_classpath/JarClasspathTest.zip +0 -0
- data/test/data/jar_classpath/JarClasspathTestManifest.jar +0 -0
- data/test/data/jar_classpath/JarClasspathTestMultiManifest.jar +0 -0
- data/test/data/jar_classpath/make.bat +24 -0
- data/test/data/jar_searcher/JarClassListTest.jar +0 -0
- data/test/data/jar_searcher/PublicClass.java +12 -0
- data/test/data/jar_searcher/PublicInterface.java +5 -0
- data/test/data/jar_searcher/make.bat +13 -0
- data/test/data/java_home_classpath/jdk/jre/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/jre/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/jre-ext/lib/ext/ext.jar +0 -0
- data/test/data/java_home_classpath/jre-ext/lib/rt.jar +0 -0
- data/test/data/java_home_classpath/make.bat +13 -0
- data/test/data/references/ReferencesTest.class +0 -0
- data/test/data/references/ReferencesTest.java +12 -0
- data/test/data/references/make.bat +5 -0
- data/test/setup.rb +6 -5
- data/test/test_access_flags.rb +59 -44
- data/test/test_base.rb +20 -15
- data/test/test_class_entry.rb +198 -0
- data/test/test_class_version.rb +48 -46
- data/test/test_composite_classpath.rb +68 -0
- data/test/test_constant_pool.rb +49 -41
- data/test/test_folder_classpath.rb +45 -0
- data/test/test_jar_classpath.rb +57 -0
- data/test/test_jar_searcher.rb +93 -0
- data/test/test_java_class_header.rb +34 -22
- data/test/test_java_home_classpath.rb +50 -0
- data/test/test_java_name.rb +110 -0
- data/test/test_javaclass.rb +22 -0
- data/test/test_list.rb +123 -0
- data/test/test_package_entry.rb +91 -0
- data/test/test_references.rb +38 -20
- data/test/test_string_ux.rb +99 -2
- data/test/ts_all_tests.rb +42 -21
- metadata +171 -50
- data/lib/javaclass/access_flags.rb +0 -44
- data/lib/javaclass/class_magic.rb +0 -27
- data/lib/javaclass/class_version.rb +0 -65
- data/lib/javaclass/constant_pool.rb +0 -85
- data/lib/javaclass/constants/base.rb +0 -31
- data/lib/javaclass/constants/double_reference.rb +0 -81
- data/lib/javaclass/constants/single_reference.rb +0 -58
- data/lib/javaclass/constants/value.rb +0 -114
- data/lib/javaclass/java_class_header.rb +0 -88
- data/lib/javaclass/references.rb +0 -31
- data/test/data/AccessFlagsTestPublic$InnerClass.class +0 -0
- data/test/data/AccessFlagsTestPublic.class +0 -0
- data/test/data/AccessFlagsTestPublic.java +0 -7
data/Rakefile
CHANGED
|
@@ -1,51 +1,236 @@
|
|
|
1
|
+
#require 'FileUtils' # already required
|
|
2
|
+
require 'net/http'
|
|
1
3
|
require 'rubygems'
|
|
2
|
-
|
|
4
|
+
require 'rubygems/gem_runner' # install and uninstall
|
|
3
5
|
require 'rake'
|
|
6
|
+
require 'rake/clean' # for clean/clobber
|
|
4
7
|
require 'rake/testtask'
|
|
5
|
-
require 'rake/packagetask'
|
|
6
8
|
require 'rake/gempackagetask'
|
|
9
|
+
require 'rake/packagetask'
|
|
7
10
|
require 'rake/rdoctask'
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
# Test, package and publish functions.
|
|
13
|
+
# Author:: Peter Kofler
|
|
14
|
+
# See: http://rake.rubyforge.org/files/doc/rakefile_rdoc.html
|
|
15
|
+
GEM_NAME = 'javaclass'
|
|
16
|
+
GOOGLE_PROJECT = "#{GEM_NAME}-rb"
|
|
17
|
+
RDOC_DIR = 'html'
|
|
18
|
+
RDOC_REPO = 'api'
|
|
10
19
|
|
|
11
20
|
gemspec = Gem::Specification.new do |s|
|
|
12
|
-
s.
|
|
13
|
-
s.
|
|
14
|
-
s.
|
|
15
|
-
s.
|
|
16
|
-
s.
|
|
17
|
-
s.
|
|
18
|
-
s.has_rdoc = true
|
|
19
|
-
s.rubyforge_project = 'javaclass'
|
|
20
|
-
s.homepage = 'http://javaclass.rubyforge.org/'
|
|
21
|
+
s.version = '0.0.3'
|
|
22
|
+
s.name = GEM_NAME
|
|
23
|
+
s.rubyforge_project = 'javaclass' # old, just redirects
|
|
24
|
+
s.summary = 'A parser and disassembler for Java class files'
|
|
25
|
+
s.description = 'Provides access to the package, protected, and public fields and methods of the classes passed to it together with a list of all outgoing references.'
|
|
26
|
+
s.homepage = "http://code.google.com/p/#{GOOGLE_PROJECT}/"
|
|
21
27
|
s.author = 'Peter Kofler'
|
|
22
|
-
s.email = '
|
|
23
|
-
|
|
28
|
+
s.email = 'peter dot kofler at code minus cop dot org'
|
|
29
|
+
|
|
30
|
+
s.files = FileList['Readme.txt', '{lib,test,examples}/**/*.*', 'history.txt', 'Rakefile']
|
|
31
|
+
s.test_files = FileList['test/**/test_*.rb']
|
|
32
|
+
s.require_path = 'lib'
|
|
33
|
+
s.add_dependency('rubyzip', '>= 0.9.1')
|
|
34
|
+
s.required_ruby_version = '>= 1.8.6'
|
|
24
35
|
s.platform = Gem::Platform::RUBY
|
|
36
|
+
s.add_development_dependency('rake', '>= 0.8.4')
|
|
37
|
+
s.add_development_dependency('ZenTest', '>= 4.4.0')
|
|
38
|
+
|
|
39
|
+
s.has_rdoc = true
|
|
40
|
+
s.extra_rdoc_files = ['Readme.txt', 'history.txt']
|
|
41
|
+
s.rdoc_options << '--title' << "#{s.name}-#{s.version} Documentation" <<
|
|
42
|
+
'--main' << 'Readme.txt'
|
|
43
|
+
end
|
|
44
|
+
full_gem_name = "#{gemspec.name}-#{gemspec.version}"
|
|
45
|
+
|
|
46
|
+
desc 'Validates the gemspec'
|
|
47
|
+
task :validate_gem do
|
|
48
|
+
gemspec.validate
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
desc 'Displays the current version'
|
|
52
|
+
task :version do
|
|
53
|
+
puts gemspec.version
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# :test
|
|
57
|
+
Rake::TestTask.new do |t|
|
|
58
|
+
t.test_files = gemspec.test_files
|
|
59
|
+
t.warning = true
|
|
60
|
+
#t.verbose = false is default
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
desc 'Find missing test methods with ZenTest'
|
|
64
|
+
task :zentest do
|
|
65
|
+
files = gemspec.files.find_all { |f| f =~ /^#{gemspec.require_path}.*\.rb$/ } + gemspec.test_files
|
|
66
|
+
output = `ruby -I#{gemspec.require_path} -e "require 'rubygems'; load(Gem.bin_path('ZenTest', 'zentest'))" #{files.join(' ')}`
|
|
67
|
+
puts output.gsub(/^#.*\n/, '') # skip all ZenTest comments
|
|
25
68
|
end
|
|
26
69
|
|
|
27
|
-
|
|
70
|
+
# :gem
|
|
71
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
|
28
72
|
pkg.need_zip = true
|
|
29
73
|
end
|
|
30
74
|
|
|
31
|
-
|
|
75
|
+
# :package, :clobber_package, :repackage
|
|
76
|
+
Rake::PackageTask.new(gemspec.name, gemspec.version) do |pkg|
|
|
32
77
|
#pkg.need_tar = true - no compress in tar on unxutils in Windows
|
|
33
78
|
#pkg.need_tar_gz = true - no compress in tar on unxutils in Windows
|
|
34
79
|
pkg.need_zip = true
|
|
35
80
|
pkg.package_files.include gemspec.files
|
|
36
81
|
end
|
|
37
82
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
83
|
+
desc 'Install the gem locally'
|
|
84
|
+
task :install_gem => :package do
|
|
85
|
+
Gem::GemRunner.new.run ['install', "pkg/#{full_gem_name}"]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
desc 'Uninstall the gem'
|
|
89
|
+
task :uninstall_gem do
|
|
90
|
+
Gem::GemRunner.new.run ['uninstall', gemspec.name]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Helper method to execute Mercurial with the _params_ array.
|
|
94
|
+
# The +hg+ executable must be in the path.
|
|
95
|
+
def hg(params)
|
|
96
|
+
puts `hg #{params.join(' ')}`
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
desc 'Tag current version in Hg'
|
|
100
|
+
task :tag do
|
|
101
|
+
hg ['tag', '-f', "-m \"Released gem version #{gemspec.version}\"", "#{full_gem_name}"]
|
|
102
|
+
puts 'Tag created. Don\'t forget to push'
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# internal - desc 'Release the gem to Rubygems'
|
|
106
|
+
task :release_rubygems => :package do
|
|
107
|
+
puts "Releasing #{full_gem_name} to Rubygems"
|
|
108
|
+
Gem::GemRunner.new.run ['push', "pkg/#{full_gem_name}.gem"]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Read username and password from the <code>~/.hgrc</code> for _authname_ prefix.
|
|
112
|
+
# <code>HOME</code> environment must be set.
|
|
113
|
+
def user_pass_from_hgrc(authname)
|
|
114
|
+
lines = IO.readlines(File.expand_path('~/.hgrc'))
|
|
115
|
+
user = lines.find{ |l| l =~ /#{authname}.username/ }[/[^\s=]+$/]
|
|
116
|
+
raise "could not find key #{authname}.username in ~/.hgrc" unless user
|
|
117
|
+
pass = lines.find{ |l| l =~ /#{authname}.password/ }[/[^\s=]+$/]
|
|
118
|
+
raise "could not find key #{authname}.password in ~/.hgrc" unless pass
|
|
119
|
+
[user, pass]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Download the <code>googlecode_upload.py</code> from Google Code repository and save it as _name_ .
|
|
123
|
+
# See:: http://support.googlecode.com/svn/trunk/scripts/googlecode_upload.py
|
|
124
|
+
def download_googlecode_upload_py(name)
|
|
125
|
+
Net::HTTP.start('support.googlecode.com', 80) do |http|
|
|
126
|
+
body = http.get("/svn/trunk/scripts/#{name}").body
|
|
127
|
+
File.open(name, 'w') { |f| f.print body }
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Helper method to execute Python with the _params_ array.
|
|
132
|
+
# The +python+ executable must be in the path.
|
|
133
|
+
def python(params)
|
|
134
|
+
puts `python #{params.join(' ')}`
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# internal - desc 'Release the gem to Google Code'
|
|
138
|
+
task :release_googlecode => :package do
|
|
139
|
+
puts "Releasing #{full_gem_name} to GoogleCode"
|
|
140
|
+
user, pass = user_pass_from_hgrc(gemspec.name)
|
|
141
|
+
# See:: http://code.google.com/p/support/wiki/ScriptedUploads
|
|
142
|
+
download_googlecode_upload_py 'googlecode_upload.py'
|
|
143
|
+
['gem', 'zip'].each do |extension|
|
|
144
|
+
puts "uploading \"pkg/#{full_gem_name}.#{extension}\"..."
|
|
145
|
+
python ['googlecode_upload.py', "-s \"JavaClass #{gemspec.version} #{extension.capitalize}\"", "-p #{GOOGLE_PROJECT}", "-u #{user}", "-w #{pass}", "pkg/#{full_gem_name}.#{extension}"]
|
|
146
|
+
end
|
|
42
147
|
end
|
|
43
148
|
|
|
149
|
+
desc 'Package and upload gem to Rubygems and Google Code'
|
|
150
|
+
task :publish_gem => [:clobber_package, :package, :release_rubygems, :release_googlecode]
|
|
151
|
+
|
|
152
|
+
# :rdoc, :clobber_rdoc, :rerdoc
|
|
44
153
|
Rake::RDocTask.new do |rdoc|
|
|
45
|
-
|
|
46
|
-
rdoc.title
|
|
47
|
-
rdoc.main
|
|
154
|
+
rdoc.rdoc_dir = RDOC_DIR # 'html' is default anyway
|
|
155
|
+
rdoc.title = "#{full_gem_name} Documentation"
|
|
156
|
+
rdoc.main = 'Readme.txt'
|
|
48
157
|
rdoc.rdoc_files.include 'Readme.txt', 'lib/**/*.rb', 'history.txt'
|
|
49
158
|
end
|
|
50
159
|
|
|
160
|
+
# Helper method to add target="_parent" to all external links in _file_ html.
|
|
161
|
+
def add_href_parent(file)
|
|
162
|
+
lines = IO.readlines(file).collect do |line|
|
|
163
|
+
if line =~ /(href=(?:'|")https?:\/\/)/
|
|
164
|
+
"#{$`}target=\"_parent\" #{$1}#{$'}"
|
|
165
|
+
else
|
|
166
|
+
line
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
File.open(file, 'w') { |f| f.print lines.join }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
desc 'Fix the RDoc hrefs in framesets'
|
|
173
|
+
task :fix_rdoc => [:rdoc] do
|
|
174
|
+
Dir["#{RDOC_DIR}/**/*.html"].each { |file| add_href_parent(file) }
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Helper method to add the gem version _dir_ into index _file_ to frameset links.
|
|
178
|
+
def add_frameset_version(file, dir)
|
|
179
|
+
lines = IO.readlines(file).collect do |line|
|
|
180
|
+
if line =~ /(frame src=")/
|
|
181
|
+
"#{$`}#{$1}#{dir}/#{$'}"
|
|
182
|
+
else
|
|
183
|
+
line
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
File.open(file, 'w') { |f| f.print lines.join }
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
desc 'Publish the RDoc files to Google Code'
|
|
190
|
+
task :publish_rdoc => [:clobber_rdoc, :rdoc, :fix_rdoc] do
|
|
191
|
+
puts "Releasing #{full_gem_name} to API"
|
|
192
|
+
|
|
193
|
+
remote_repo = "https://#{RDOC_REPO}.#{GOOGLE_PROJECT}.googlecode.com/hg/"
|
|
194
|
+
remote_dir = "#{gemspec.version}"
|
|
195
|
+
|
|
196
|
+
FileUtils.rm_r RDOC_REPO rescue nil
|
|
197
|
+
hg ['clone', remote_repo, RDOC_REPO]
|
|
198
|
+
|
|
199
|
+
FileUtils.rm_r "#{RDOC_REPO}/#{remote_dir}" rescue nil
|
|
200
|
+
FileUtils.cp_r RDOC_DIR, "#{RDOC_REPO}/#{remote_dir}"
|
|
201
|
+
|
|
202
|
+
# modify index, update redirect in frameset
|
|
203
|
+
file = "#{RDOC_REPO}/index.html"
|
|
204
|
+
FileUtils.cp "#{RDOC_REPO}/#{remote_dir}/index.html", file
|
|
205
|
+
add_frameset_version(file, remote_dir)
|
|
206
|
+
|
|
207
|
+
hg ['addremove', '-q', "-R #{RDOC_REPO}"]
|
|
208
|
+
hg ['ci', "-m \"Update Rdoc for version #{gemspec.version}\"", "-R #{RDOC_REPO}"]
|
|
209
|
+
hg ['tag', '-f', "-m \"Released gem version #{gemspec.version}\"", "-R #{RDOC_REPO}", "#{full_gem_name}"]
|
|
210
|
+
hg ['push', "-R #{RDOC_REPO}"]
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# :clean :clobber
|
|
214
|
+
CLOBBER.include(RDOC_REPO, 'googlecode_upload.py')
|
|
215
|
+
|
|
216
|
+
# Helper method to grep all the sources for some _pattern_ words.
|
|
217
|
+
def egrep(pattern)
|
|
218
|
+
Dir['**/*'].find_all { |fn| FileTest.file? fn }.each do |fn|
|
|
219
|
+
line_count = 0
|
|
220
|
+
open(fn) do |f|
|
|
221
|
+
while line = f.gets
|
|
222
|
+
line_count += 1
|
|
223
|
+
if line =~ pattern
|
|
224
|
+
puts "#{fn}:#{line_count}:#{line.strip}"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
desc 'Look for TODO and FIXME tags'
|
|
232
|
+
task :todo do
|
|
233
|
+
egrep(/#.*(FI[X]ME|TO[D]O|T[B]D|H[A]CK)/i) # use 'odd' brackets to not find myself (and not have Eclipse markers)
|
|
234
|
+
end
|
|
235
|
+
|
|
51
236
|
task :default => :test
|
data/Readme.txt
CHANGED
|
@@ -1,47 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
by {Peter Kofler}[http://
|
|
1
|
+
javaclass-rb
|
|
2
|
+
by {Peter 'Code Cop' Kofler}[http://www.code-cop.org/]
|
|
3
3
|
|
|
4
|
-
* {Homepage}[http://
|
|
5
|
-
* {Rubyforge Project}[http://rubyforge.org/projects/javaclass]
|
|
6
|
-
* email
|
|
4
|
+
* {Homepage (Google Code)}[http://code.google.com/p/javaclass-rb/]
|
|
5
|
+
* {Rubyforge Project (old)}[http://rubyforge.org/projects/javaclass]
|
|
6
|
+
* email peter dot kofler at code minus cop dot org
|
|
7
7
|
|
|
8
8
|
== Description
|
|
9
9
|
|
|
10
|
-
|
|
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.
|
|
10
|
+
javaclass-rb (Java Class File Parser for Ruby) 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
14
|
|
|
15
15
|
== Motivation
|
|
16
16
|
|
|
17
|
-
I am still doing Java most of the time. I used to be quite
|
|
18
|
-
it, but after
|
|
19
|
-
Ruby for all kind of stuff, just for fun.
|
|
20
|
-
analysis
|
|
17
|
+
I am still doing Java most of the time. I used to be quite enthusiastic about
|
|
18
|
+
it, but after 11 years I can see the advantages of being a polyglot. So I use
|
|
19
|
+
Ruby for all kind of stuff, just for fun. When I needed some Java class
|
|
20
|
+
analysis I wrote it with Ruby. As I am a puritan, I did not
|
|
21
21
|
want to call javap from my script, so I started disassembling the class files,
|
|
22
|
-
which might be the
|
|
23
|
-
started adding methods to that end...)
|
|
22
|
+
which might be the base for some serious static code analysis tools. (I
|
|
23
|
+
started adding methods to that end...)
|
|
24
24
|
|
|
25
25
|
== Install
|
|
26
26
|
|
|
27
27
|
sudo gem install javaclass
|
|
28
28
|
|
|
29
|
+
* {Gem Hosting}[http://rubygems.org/gems/javaclass]
|
|
30
|
+
* {Download of tarballs and gems}[http://code.google.com/p/javaclass-rb/downloads/list]
|
|
31
|
+
|
|
29
32
|
== Usage
|
|
30
33
|
|
|
31
34
|
require 'javaclass'
|
|
35
|
+
|
|
36
|
+
# load the class directly from the file system
|
|
37
|
+
clazz = JavaClass.load_fs('packagename/Public.class')
|
|
38
|
+
|
|
39
|
+
# better lookup the class from some classpath
|
|
40
|
+
classpath = JavaClass.classpath('some/path')
|
|
41
|
+
clazz = JavaClass.load_cp('packagename.Public', classpath)
|
|
32
42
|
|
|
33
|
-
clazz = JavaClass.parse('packagename/Public.class')
|
|
34
43
|
clazz.version # => 50.0
|
|
35
44
|
clazz.constant_pool.items[1] # => packagename/Public
|
|
36
45
|
clazz.access_flags.public? # => true
|
|
37
46
|
clazz.this_class # => packagename/Public
|
|
47
|
+
clazz.this_class.to_java_file # => packagename/Public.java
|
|
38
48
|
clazz.super_class # => java/lang/Object
|
|
49
|
+
clazz.super_class.to_classname # => java.lang.Object
|
|
39
50
|
clazz.references.referenced_methods[0] # => java/lang/Object.<init>:()V
|
|
40
51
|
|
|
41
|
-
==
|
|
52
|
+
== Documentation
|
|
53
|
+
|
|
54
|
+
Module +JavaClass+ is the entry point for most functions in the gem.
|
|
55
|
+
The main class is JavaClass::ClassFile::JavaClassHeader which provides access to
|
|
56
|
+
all information of a Java class file. There are also some examples in the examples
|
|
57
|
+
folder of the gem.
|
|
58
|
+
|
|
59
|
+
* {API RDoc}[http://api.javaclass-rb.googlecode.com/hg/index.html]
|
|
60
|
+
|
|
61
|
+
== Support
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
The bug tracker is available at http://code.google.com/p/javaclass-rb/issues/list or just drop me an email.
|
|
64
|
+
|
|
65
|
+
== Dependencies
|
|
66
|
+
|
|
67
|
+
* Ruby 1.8.6
|
|
68
|
+
* {rubyzip}[http://rubyzip.sourceforge.net/]
|
|
69
|
+
|
|
70
|
+
== References
|
|
71
|
+
|
|
72
|
+
* {JavaWorld: The Java class file lifestyle}[http://www.javaworld.com/javaworld/jw-07-1996/jw-07-classfile.html]
|
|
73
|
+
* {VM Spec: The class File Format}[http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html]
|
|
74
|
+
* {Similar Project by unageanu}[http://github.com/unageanu/javaclass]
|
|
44
75
|
|
|
45
76
|
== License
|
|
46
77
|
|
|
47
|
-
|
|
78
|
+
* {New BSD License}[http://www.opensource.org/licenses/bsd-license.php]
|
|
79
|
+
|
|
80
|
+
== Disclaimer Note
|
|
81
|
+
|
|
82
|
+
This software is provided "as is" and without any express or implied warranties,
|
|
83
|
+
including, without limitation, the implied warranties of merchantability and
|
|
84
|
+
fitness for a particular purpose.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
|
2
|
+
require 'javaclass/classlist/list'
|
|
3
|
+
require 'javaclass/classlist/jar_searcher'
|
|
4
|
+
|
|
5
|
+
# Generate the full class lists starting from a saved one.
|
|
6
|
+
# Author:: Peter Kofler
|
|
7
|
+
puts "create full class lists for JDKs (by search and open class)"
|
|
8
|
+
|
|
9
|
+
# Struct to keep configuration what kind of JDK classes should be searched and added.
|
|
10
|
+
JDK_CONFIG = Struct.new(:version, :label, :paths)
|
|
11
|
+
# Define information about JDK to process one after another.
|
|
12
|
+
JDKS = [
|
|
13
|
+
JDK_CONFIG.new(0, "1.0.2", ['E:\Develop\Java\Compiler\jdk1.0.2\lib']),
|
|
14
|
+
JDK_CONFIG.new(1, "1.1.8-09", ['E:\Develop\Java\Compiler\jdk1.1.8\lib', 'E:\Develop\Java\JDK-1.1\Library\swing-1.1.1\lib']),
|
|
15
|
+
JDK_CONFIG.new(2, "1.2.2-13", ['C:\Programme\Java\jdk1.2.2_13\jre\lib', 'C:\Programme\Java\jdk1.2.2_13\lib\dt.jar']),
|
|
16
|
+
JDK_CONFIG.new(3, "1.3.1-08", ['C:\Programme\Java\jdk1.3.1_08\jre\lib', 'C:\Programme\Java\jdk1.3.1_08\lib\dt.jar']),
|
|
17
|
+
JDK_CONFIG.new(4, "1.4.2-03", ['C:\Programme\Java\jdk1.4.2_03\jre\lib', 'C:\Programme\Java\jdk1.4.2_03\lib\dt.jar']),
|
|
18
|
+
JDK_CONFIG.new(5, "1.5.0-07", ['C:\Programme\Java\jdk1.5.0_07\jre\lib', 'C:\Programme\Java\jdk1.5.0_07\lib\dt.jar']),
|
|
19
|
+
JDK_CONFIG.new(6, "1.6.0-11", ['C:\Programme\Java\jdk1.6.0_21\jre\lib', 'C:\Programme\Java\jdk1.6.0_21\lib\dt.jar']),
|
|
20
|
+
#JDK_CONFIG.new(7, "1.7.0-xx", ['C:\Programme\Java\jdk1.7.0_xx\jre\lib']),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
BASE_NAME = 'fullClassList'
|
|
24
|
+
|
|
25
|
+
# Create a new list
|
|
26
|
+
@list = JavaClass::ClassList::List.new
|
|
27
|
+
|
|
28
|
+
# load already good list if we do not start with JDK 1.0
|
|
29
|
+
if JDKS[0].version > 0
|
|
30
|
+
old_version = JDKS[0].version-1
|
|
31
|
+
old_class_list_name = Dir["./#{BASE_NAME}?#{old_version}?.txt"].first
|
|
32
|
+
if FileTest.exist?(old_class_list_name)
|
|
33
|
+
puts "loading #{old_version}"
|
|
34
|
+
IO.readlines(old_class_list_name).each {|line| @list.parse_line(line, old_version) }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# init the searcher
|
|
39
|
+
@searcher = JavaClass::ClassList::JarSearcher.new
|
|
40
|
+
@searcher.filters = %w[sun/ sunw/ com/sun/ netscape/ COM/rsa/ quicktime/ com/apple/mrj/macos/carbon/ org/jcp/xml/dsig/internal/]
|
|
41
|
+
# netscape ... applet js security [2]
|
|
42
|
+
# COM/rsa/ ... jsafe [4]
|
|
43
|
+
# quicktime ... quicktime [5]
|
|
44
|
+
# org/jcp/xml/dsig/internal ... xml dsig [6]
|
|
45
|
+
|
|
46
|
+
#Dir.mkdir './ClassLists' unless File.exist? './ClassLists'
|
|
47
|
+
|
|
48
|
+
# Work on all lists defined in +JDK+ and yield the block with the jdk label and the class list.
|
|
49
|
+
JDKS.each do |conf|
|
|
50
|
+
puts "processing #{conf.version}"
|
|
51
|
+
conf.paths.each { |p| @list = @searcher.compile_list(conf.version, p, @list) }
|
|
52
|
+
|
|
53
|
+
#basename = "jdk#{conf.label.gsub(/\./, '')}"
|
|
54
|
+
#File.open("./ClassLists/#{basename}_new_package_classes.txt", "w") { |f| f.print @list.old_access_list.collect{|m| m.sub(/\s.*$/, '')} }
|
|
55
|
+
#File.open("./ClassLists/#{basename}_all_classes.txt", "w") { |f| f.print @list.plain_class_list }
|
|
56
|
+
#File.open("./ClassLists/#{basename}_all_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? } }
|
|
57
|
+
#File.open("./ClassLists/#{basename}_new_public_classes.txt", "w") { |f| f.print @list.plain_class_list { |c| c.public? and c.version.first == conf.version } }
|
|
58
|
+
|
|
59
|
+
baseversion = conf.label.gsub(/\.|-.+$/, '')
|
|
60
|
+
File.open("./#{BASE_NAME}#{baseversion}.txt", "w") { |f| f.print @list.full_class_list }
|
|
61
|
+
end
|
data/history.txt
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
=== 0.0.3 02/10/2010
|
|
2
|
+
|
|
3
|
+
* integrated ClassList from another project as first analyser
|
|
4
|
+
* add JavaName to all class names that are returned
|
|
5
|
+
* fix links in RDoc, update documentation
|
|
6
|
+
* move classes into submodules for classpath, classfile, etc.
|
|
7
|
+
* migrated to Google Code and Mercurial repository
|
|
8
|
+
* added access flag $1000
|
|
9
|
+
* added references to used classes
|
|
10
|
+
* added classpath abstraction
|
|
11
|
+
|
|
1
12
|
=== 0.0.2 08/04/2009
|
|
2
13
|
|
|
3
14
|
* refactored code to smaller objects for version and constant pool
|
|
@@ -8,22 +19,5 @@
|
|
|
8
19
|
=== 0.0.1 01/03/2009
|
|
9
20
|
|
|
10
21
|
* initial version extracted from ClassList project
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
22
|
+
* reads the class version and package/public flag of a class
|
|
23
|
+
* understands the constant pool but does not use it
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'javaclass/string_ux'
|
|
2
|
+
|
|
3
|
+
module JavaClass
|
|
4
|
+
module ClassFile
|
|
5
|
+
|
|
6
|
+
# The access flags of a class or interface.
|
|
7
|
+
# Author:: Peter Kofler
|
|
8
|
+
class AccessFlags
|
|
9
|
+
|
|
10
|
+
# Access flags as defined by JVM spec.
|
|
11
|
+
ACC_PUBLIC = 0x0001
|
|
12
|
+
ACC_FINAL = 0x0010
|
|
13
|
+
ACC_SUPER = 0x0020 # old invokespecial instruction semantics
|
|
14
|
+
ACC_INTERFACE = 0x0200
|
|
15
|
+
ACC_ABSTRACT = 0x0400
|
|
16
|
+
ACC_INNER = 0x1000 # TODO unknown access flag, find in spec
|
|
17
|
+
ACC_OTHER = 0xffff ^ ACC_PUBLIC ^ ACC_FINAL ^ ACC_SUPER ^ ACC_INTERFACE ^ ACC_ABSTRACT ^ ACC_INNER
|
|
18
|
+
|
|
19
|
+
def initialize(data, pos)
|
|
20
|
+
@flags = data.u2(pos)
|
|
21
|
+
raise "inconsistent flags #{@flags} (abstract and final)" if abstract? && final?
|
|
22
|
+
if interface? && !abstract?
|
|
23
|
+
# JDK 1.0 and 1.1 do have non abstract interfaces, fix it
|
|
24
|
+
@flags = @flags | ACC_ABSTRACT
|
|
25
|
+
end
|
|
26
|
+
raise "inconsistent flags #{@flags} (interface not abstract)" if interface? && !abstract?
|
|
27
|
+
raise "inconsistent flags #{@flags} (interface is final)" if interface? && final?
|
|
28
|
+
raise "inconsistent flags #{@flags} (other value #{@flags & ACC_OTHER})" if (@flags & ACC_OTHER) != 0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Return +true+ if the class is public.
|
|
32
|
+
def public?
|
|
33
|
+
(@flags & ACC_PUBLIC) != 0
|
|
34
|
+
end
|
|
35
|
+
alias accessible? public?
|
|
36
|
+
|
|
37
|
+
def final?
|
|
38
|
+
(@flags & ACC_FINAL) != 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def abstract?
|
|
42
|
+
(@flags & ACC_ABSTRACT) != 0
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def interface?
|
|
46
|
+
(@flags & ACC_INTERFACE) != 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module JavaClass
|
|
2
|
+
module ClassFile
|
|
3
|
+
|
|
4
|
+
# The +CAFEBABE+ magic of a class file. This just checks if CAFEBABE is here.
|
|
5
|
+
# Author:: Peter Kofler
|
|
6
|
+
class ClassMagic # ZenTest SKIP
|
|
7
|
+
|
|
8
|
+
CAFE_BABE = "\xCA\xFE\xBA\xBE"
|
|
9
|
+
|
|
10
|
+
# Check the class magic in the _data_ beginning at position _start_ (which is usually 0).
|
|
11
|
+
def initialize(data, start=0)
|
|
12
|
+
# "parsing"
|
|
13
|
+
@bytes = data[start..start+3]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return +true+ if the data was valid, i.e. if the class started with +CAFEBABE+.
|
|
17
|
+
def valid?
|
|
18
|
+
@bytes == CAFE_BABE
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Return the value of the magic in this class.
|
|
22
|
+
def bytes
|
|
23
|
+
@bytes.dup
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'javaclass/string_ux'
|
|
2
|
+
|
|
3
|
+
module JavaClass
|
|
4
|
+
module ClassFile
|
|
5
|
+
|
|
6
|
+
# Version of a class file.
|
|
7
|
+
# Author:: Peter Kofler
|
|
8
|
+
# See:: http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#75883
|
|
9
|
+
class ClassVersion # ZenTest FULL to find method to_s
|
|
10
|
+
|
|
11
|
+
attr_reader :minor
|
|
12
|
+
attr_reader :major
|
|
13
|
+
|
|
14
|
+
# Extract the class version from the bytes _data_ starting at position _start_ (which is usually 4).
|
|
15
|
+
def initialize(data, start=4)
|
|
16
|
+
# parsing
|
|
17
|
+
@minor = data.u2(start)
|
|
18
|
+
@major = data.u2(start+2)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Return the class file version as +major+.+minor+ string like 48.0 (Java 1.4) or 50.0 (Java 6).
|
|
22
|
+
def to_s
|
|
23
|
+
"#{@major}.#{@minor}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Return the version as +major+.+minor+ float.
|
|
27
|
+
def to_f
|
|
28
|
+
if @minor <= 0
|
|
29
|
+
denom = 1.0
|
|
30
|
+
else
|
|
31
|
+
denom = 1.0 * 10**(Math.log10(@minor).floor + 1)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@major + @minor/denom
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Return a debug output of this version.
|
|
38
|
+
def dump
|
|
39
|
+
[" minor version: #{@minor}", " major version: #{@major}"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Return the JDK version corresponding to this version like "1.6" or "unknown" if none matched.
|
|
43
|
+
def jdk_version
|
|
44
|
+
v = to_f
|
|
45
|
+
if v >= 45.0 && v <= 45.3 # 1.0.2 supports class file format versions 45.0 through 45.3 inclusive.
|
|
46
|
+
'1.0'
|
|
47
|
+
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
|
|
48
|
+
'1.1'
|
|
49
|
+
elsif v == 46.0 # JDK 1.2=46
|
|
50
|
+
'1.2'
|
|
51
|
+
elsif v == 47.0 # JDK 1.3=47
|
|
52
|
+
'1.3'
|
|
53
|
+
elsif v == 48.0 # JDK 1.4=48
|
|
54
|
+
'1.4'
|
|
55
|
+
elsif v == 49.0 # J2SE 5.0=49
|
|
56
|
+
'1.5'
|
|
57
|
+
elsif v == 50.0 # J2SE 6.0=50
|
|
58
|
+
'1.6'
|
|
59
|
+
else
|
|
60
|
+
'unknown'
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|