mirror of
https://github.com/zhigang1992/RubyMotion.git
synced 2026-04-08 22:43:35 +08:00
113 lines
3.1 KiB
Ruby
Executable File
113 lines
3.1 KiB
Ruby
Executable File
#!/usr/bin/ruby
|
|
# encoding: utf-8
|
|
|
|
require 'fileutils'
|
|
require 'pathname'
|
|
require 'optparse'
|
|
|
|
def gen_bridge_metadata(file)
|
|
|
|
file = File.expand_path(file)
|
|
|
|
case ext = File.extname(file)
|
|
when '.jar'
|
|
class_path = File.join(ENV['TMPDIR'], '__android_bridgesupport__', File.basename(file))
|
|
FileUtils.rm_rf class_path
|
|
FileUtils.mkdir_p class_path
|
|
puts "Extracting #{file} to #{class_path}" if ENV['DEBUG']
|
|
exit 1 unless system "/usr/bin/unzip -q \"#{file}\" -d \"#{class_path}\""
|
|
|
|
classes = Dir.glob(File.join(class_path ,"**/*.class")).map { |c| c.gsub(class_path, '') }
|
|
when '.class'
|
|
class_path = File.dirname(file)
|
|
classes = [File.basename(file)]
|
|
else
|
|
die "Invalid file extension '#{ext}'. Supported extensions are 'jar' and 'class'"
|
|
end
|
|
|
|
# Decompile classes.
|
|
classes = classes.map { |x| x.gsub('/', '.').gsub('$', '.').sub(/\.class$/, '') }
|
|
txt = `/usr/bin/javap -classpath "#{class_path}" -s #{classes.join(' ')}`
|
|
|
|
# Create the BridgeSupport text.
|
|
res = txt.scan(/(class)\s+([^\s]+)\s+extends\s+[^{]+\s*\{([^}]+)\}/)
|
|
res += txt.scan(/(class)\s([^\s{]+)\s*\{([^}]+)\}/) # Also grab classes without superclasses (ex. java.lang.Object)
|
|
res += txt.scan(/(interface)\s([^\s{]+)\s*\{([^}]+)\}/) # Also grab interfaces
|
|
res.each do |type, elem, body_txt|
|
|
elem_path = encode_xml(elem.gsub(/\./, '/'))
|
|
@bs_data << <<EOS
|
|
<#{type} name=\"#{elem_path}\">
|
|
EOS
|
|
body_txt.strip.split(/\n/).each_cons(2) do |elem_line, signature_line|
|
|
signature_line = encode_xml(signature_line.strip)
|
|
md = signature_line.match(/^Signature:\s+(.+)$/)
|
|
next unless md
|
|
signature = md[1]
|
|
|
|
elem_line = encode_xml(elem_line.strip)
|
|
if md = elem_line.match(/\s([^(\s]+)\(/)
|
|
# A method.
|
|
method = md[1]
|
|
if method == elem
|
|
# An initializer.
|
|
method = '<init>'
|
|
end
|
|
class_method = elem_line.include?('static')
|
|
@bs_data << <<EOS
|
|
<method name=\"#{method}\" type=\"#{signature}\"#{class_method ? ' class_method="true"' : ''}/>
|
|
EOS
|
|
elsif md = elem_line.match(/\s([^;\s]+);$/)
|
|
=begin
|
|
# A constant.
|
|
constant = md[1]
|
|
@bs_data << <<EOS
|
|
<const name=\"#{constant}\" type=\"#{signature}\"/>
|
|
EOS
|
|
=end
|
|
end
|
|
end
|
|
@bs_data << <<EOS
|
|
</#{type}>
|
|
EOS
|
|
end
|
|
end
|
|
|
|
def encode_xml(string)
|
|
string.gsub(/[&<>"]/, ">" => ">", "<" => "<", "&" => "&", '"' => """)
|
|
end
|
|
|
|
def die(*msg)
|
|
$stderr.puts msg
|
|
exit 1
|
|
end
|
|
|
|
if __FILE__ == $0
|
|
OptionParser.new do |opts|
|
|
opts.banner = "Usage: #{File.basename(__FILE__)} [options] [<jar-file>|<class-file>...]"
|
|
opts.separator ''
|
|
opts.separator 'Options:'
|
|
|
|
opts.on('-o', '--output FILE', 'Write output to the given file.') do |opt|
|
|
die 'Output file can\'t be specified more than once' if @out_file
|
|
@out_file = opt
|
|
end
|
|
|
|
if ARGV.empty?
|
|
die opts.banner
|
|
else
|
|
opts.parse!(ARGV)
|
|
@bs_data = ''
|
|
@bs_data << <<EOS
|
|
<?xml version='1.0'?>
|
|
<signatures version='1.0'>
|
|
EOS
|
|
ARGV.each { |file| gen_bridge_metadata(file) }
|
|
|
|
@bs_data << <<EOS
|
|
</signatures>
|
|
EOS
|
|
File.open(@out_file, 'w') { |io| io.write(@bs_data) }
|
|
end
|
|
end
|
|
end
|