furnace-avm2 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/Gemfile.lock +2 -2
  2. data/bin/furnace-avm2 +5 -1
  3. data/bin/furnace-avm2-decompiler +80 -13
  4. data/bin/furnace-avm2-shell +32 -0
  5. data/furnace-avm2.gemspec +1 -1
  6. data/lib/furnace-avm2/abc.rb +1 -7
  7. data/lib/furnace-avm2/abc/metadata/file.rb +65 -0
  8. data/lib/furnace-avm2/abc/metadata/instance_info.rb +17 -11
  9. data/lib/furnace-avm2/abc/metadata/metadata_info.rb +14 -4
  10. data/lib/furnace-avm2/abc/metadata/method_body_info.rb +11 -3
  11. data/lib/furnace-avm2/abc/metadata/method_info.rb +3 -4
  12. data/lib/furnace-avm2/abc/metadata/multiname_kind_genericname.rb +3 -2
  13. data/lib/furnace-avm2/abc/metadata/multiname_kind_multiname.rb +11 -2
  14. data/lib/furnace-avm2/abc/metadata/multiname_kind_multinamel.rb +4 -0
  15. data/lib/furnace-avm2/abc/metadata/multiname_kind_qname.rb +10 -2
  16. data/lib/furnace-avm2/abc/metadata/multiname_kind_rtqname.rb +4 -0
  17. data/lib/furnace-avm2/abc/metadata/multiname_kind_rtqnamel.rb +4 -0
  18. data/lib/furnace-avm2/abc/metadata/script_info.rb +11 -7
  19. data/lib/furnace-avm2/abc/metadata/trait_class.rb +2 -2
  20. data/lib/furnace-avm2/abc/metadata/trait_info.rb +1 -1
  21. data/lib/furnace-avm2/abc/metadata/trait_method.rb +4 -3
  22. data/lib/furnace-avm2/abc/metadata/trait_slot.rb +2 -2
  23. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_extend_1.rb +8 -0
  24. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_extend_16.rb +8 -0
  25. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_extend_8.rb +8 -0
  26. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_load_float32.rb +8 -0
  27. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_load_float64.rb +8 -0
  28. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_load_int16.rb +8 -0
  29. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_load_int32.rb +8 -0
  30. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_load_int8.rb +8 -0
  31. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_store_float32.rb +8 -0
  32. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_store_float64.rb +8 -0
  33. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_store_int16.rb +8 -0
  34. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_store_int32.rb +8 -0
  35. data/lib/furnace-avm2/abc/opcodes/alchemy/alchemy_store_int8.rb +8 -0
  36. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_add.rb +1 -1
  37. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_add_i.rb +1 -1
  38. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_declocal.rb +1 -1
  39. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_declocal_i.rb +1 -1
  40. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_decrement.rb +1 -1
  41. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_decrement_i.rb +1 -1
  42. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_divide.rb +1 -1
  43. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_equals.rb +1 -1
  44. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_greaterequals.rb +1 -1
  45. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_greaterthan.rb +1 -1
  46. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_inclocal.rb +1 -1
  47. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_inclocal_i.rb +1 -1
  48. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_increment.rb +1 -1
  49. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_increment_i.rb +1 -1
  50. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_lessequals.rb +1 -1
  51. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_lessthan.rb +1 -1
  52. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_modulo.rb +1 -1
  53. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_multiply.rb +1 -1
  54. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_multiply_i.rb +1 -1
  55. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_negate.rb +1 -1
  56. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_negate_i.rb +1 -1
  57. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_not.rb +1 -1
  58. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_strictequals.rb +1 -1
  59. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_subtract.rb +1 -1
  60. data/lib/furnace-avm2/abc/opcodes/arithmetic/as3_subtract_i.rb +1 -1
  61. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_bitand.rb +1 -1
  62. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_bitnot.rb +1 -1
  63. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_bitor.rb +1 -1
  64. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_bitxor.rb +1 -1
  65. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_lshift.rb +1 -1
  66. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_rshift.rb +1 -1
  67. data/lib/furnace-avm2/abc/opcodes/bitwise/as3_urshift.rb +1 -1
  68. data/lib/furnace-avm2/abc/opcodes/control_transfer/as3_lookupswitch.rb +1 -1
  69. data/lib/furnace-avm2/abc/opcodes/control_transfer_opcode.rb +0 -4
  70. data/lib/furnace-avm2/abc/opcodes/exception/as3_newcatch.rb +1 -1
  71. data/lib/furnace-avm2/abc/opcodes/function_invocation/as3_callproplex.rb +4 -0
  72. data/lib/furnace-avm2/abc/opcodes/function_invocation_opcode.rb +4 -0
  73. data/lib/furnace-avm2/abc/opcodes/function_return/as3_returnvalue.rb +1 -1
  74. data/lib/furnace-avm2/abc/opcodes/function_return/as3_returnvoid.rb +1 -1
  75. data/lib/furnace-avm2/abc/opcodes/generic/as3_escxattr.rb +1 -1
  76. data/lib/furnace-avm2/abc/opcodes/generic/as3_escxelem.rb +8 -0
  77. data/lib/furnace-avm2/abc/opcodes/generic/as3_getlex.rb +4 -0
  78. data/lib/furnace-avm2/abc/opcodes/object_manipulation/as3_newfunction.rb +5 -1
  79. data/lib/furnace-avm2/abc/opcodes/property/as3_constructprop.rb +4 -0
  80. data/lib/furnace-avm2/abc/opcodes/property_opcode.rb +4 -0
  81. data/lib/furnace-avm2/abc/opcodes/push_literal/as3_pushuint.rb +11 -0
  82. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_applytype.rb +1 -1
  83. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_coerce.rb +5 -1
  84. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_coerce_a.rb +1 -1
  85. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_coerce_b.rb +1 -1
  86. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_coerce_s.rb +1 -1
  87. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_convert_d.rb +1 -1
  88. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_convert_i.rb +1 -1
  89. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_convert_o.rb +1 -1
  90. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_convert_s.rb +1 -1
  91. data/lib/furnace-avm2/abc/opcodes/type_conversion/as3_convert_u.rb +1 -1
  92. data/lib/furnace-avm2/abc/primitives/opcode_sequence.rb +35 -23
  93. data/lib/furnace-avm2/abc/primitives/record.rb +11 -0
  94. data/lib/furnace-avm2/binary/record.rb +9 -7
  95. data/lib/furnace-avm2/source/declaration_tokens/callee_token.rb +8 -5
  96. data/lib/furnace-avm2/source/declaration_tokens/class_implementations_token.rb +5 -1
  97. data/lib/furnace-avm2/source/declaration_tokens/class_specifiers_token.rb +2 -1
  98. data/lib/furnace-avm2/source/declaration_tokens/class_token.rb +5 -1
  99. data/lib/furnace-avm2/source/declaration_tokens/metadata_token.rb +25 -0
  100. data/lib/furnace-avm2/source/declaration_tokens/method_specifiers_token.rb +4 -3
  101. data/lib/furnace-avm2/source/declaration_tokens/method_token.rb +1 -0
  102. data/lib/furnace-avm2/source/declaration_tokens/multiname_token.rb +28 -13
  103. data/lib/furnace-avm2/source/declaration_tokens/package_token.rb +9 -8
  104. data/lib/furnace-avm2/source/declaration_tokens/scope_token.rb +2 -0
  105. data/lib/furnace-avm2/source/declaration_tokens/script_token.rb +4 -1
  106. data/lib/furnace-avm2/source/declaration_tokens/slot_token.rb +1 -0
  107. data/lib/furnace-avm2/source/declaration_tokens/specifiers_token.rb +11 -9
  108. data/lib/furnace-avm2/source/decompiler.rb +372 -101
  109. data/lib/furnace-avm2/source/implementation_tokens/closure_name_token.rb +7 -0
  110. data/lib/furnace-avm2/source/implementation_tokens/closure_token.rb +9 -0
  111. data/lib/furnace-avm2/source/implementation_tokens/instance_of_token.rb +9 -0
  112. data/lib/furnace-avm2/source/implementation_tokens/supplementary_comment_token.rb +16 -0
  113. data/lib/furnace-avm2/source/implementation_tokens/xml_literal_token.rb +14 -0
  114. data/lib/furnace-avm2/transform/ast_build.rb +3 -2
  115. data/lib/furnace-avm2/transform/ast_normalize.rb +39 -7
  116. data/lib/furnace-avm2/transform/cfg_build.rb +16 -6
  117. data/lib/furnace-avm2/transform/cfg_reduce.rb +4 -3
  118. data/lib/furnace-avm2/transform/nf_normalize.rb +15 -7
  119. data/lib/furnace-avm2/version.rb +1 -1
  120. data/test/basic.as +15 -0
  121. data/test/global.as +11 -0
  122. metadata +46 -29
  123. data/bin/furnace-avm2-benchmark +0 -38
  124. data/lib/furnace-avm2/abc/opcodes/arithmetic_opcode.rb +0 -4
  125. data/lib/furnace-avm2/abc/opcodes/bitwise_opcode.rb +0 -4
  126. data/lib/furnace-avm2/abc/opcodes/exception_opcode.rb +0 -4
  127. data/lib/furnace-avm2/abc/opcodes/function_return_opcode.rb +0 -4
  128. data/lib/furnace-avm2/abc/opcodes/object_manipulation_opcode.rb +0 -4
  129. data/lib/furnace-avm2/abc/opcodes/type_conversion_opcode.rb +0 -4
@@ -2,13 +2,13 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  furnace-avm2 (0.9.0)
5
- furnace (>= 0.1.0)
5
+ furnace (>= 0.1.1)
6
6
  trollop
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
- furnace (0.1.0)
11
+ furnace (0.1.1)
12
12
  trollop (1.16.2)
13
13
 
14
14
  PLATFORMS
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "rubygems"
4
- require "bundler/setup"
5
4
 
6
5
  $: << File.join(File.dirname(__FILE__), '..', 'lib')
7
6
 
@@ -38,6 +37,7 @@ EOS
38
37
  opt :cfg, "Emit CFG in Graphviz format for methods", :default => false, :short => '-C'
39
38
 
40
39
  opt :dce, "Eliminate dead code", :default => false
40
+ opt :fix_names, "Remove invalid characters from names", :default => true, :short => '-q'
41
41
  opt :ast, "Build AST", :default => false
42
42
  opt :nf, "Build NF-AST", :default => false
43
43
  opt :decompile, "Decompile methods", :default => false
@@ -77,6 +77,10 @@ failed = []
77
77
  dced = []
78
78
  smallest = nil
79
79
 
80
+ if opts[:fix_names]
81
+ abc.fix_names!
82
+ end
83
+
80
84
  if opts[:grep]
81
85
  regexp = Regexp.new(opts[:grep])
82
86
 
@@ -33,6 +33,8 @@ EOS
33
33
  opt :except, "Operate on all classes except <s+>", :type => :strings, :short => '-E'
34
34
  opt :grep, "Search <s> (regexp) in class names", :type => :string, :short => '-G'
35
35
 
36
+ opt :no_output, "Don't write out any code", :default => false
37
+
36
38
  opt :decompile, "Write ActionScript 3 code", :type => :boolean, :short => '-d'
37
39
  opt :destructurize, "Write internal token structure", :type => :boolean, :short => '-s'
38
40
  end
@@ -84,6 +86,19 @@ if opts[:grep]
84
86
  exit
85
87
  end
86
88
 
89
+ global_slots = {}
90
+
91
+ abc.scripts.each do |script|
92
+ (script.slot_traits + script.const_traits).each do |trait|
93
+ next if trait.idx == 0
94
+ global_slots[trait.idx] = trait
95
+ end
96
+ end
97
+
98
+ decompile_options[:global_slots] = global_slots
99
+
100
+ start_time = Time.now
101
+
87
102
  mutex = Mutex.new
88
103
 
89
104
  roots = {}
@@ -92,7 +107,32 @@ total_size = workqueue.size
92
107
 
93
108
  last_percentage = 0
94
109
 
95
- $stderr.puts "Decompiling #{total_size} classes and packages..."
110
+ stat = {
111
+ total: 0,
112
+ success: 0,
113
+ partial: 0,
114
+ failed: 0,
115
+ }
116
+
117
+ $stderr.puts "Found #{total_size} classes and packages."
118
+
119
+ stick = %w(| / - \\)
120
+ stick_state = 0
121
+ stick_timer = 0
122
+
123
+ progress_thread = Thread.new do
124
+ loop do
125
+ stick_timer += 1
126
+ if stick_timer % 10 == 0
127
+ $stderr.print "\e[KDecompiling... #{total_size - workqueue.size}/#{total_size} "
128
+ $stderr.print stick[stick_state]
129
+ $stderr.print "\e[0G"
130
+ stick_state = (stick_state + 1) % stick.count
131
+ end
132
+
133
+ sleep
134
+ end
135
+ end
96
136
 
97
137
  opts[:threads].times.map do
98
138
  Thread.new do
@@ -100,12 +140,6 @@ opts[:threads].times.map do
100
140
  what = nil
101
141
  mutex.synchronize do
102
142
  what = workqueue.pop
103
-
104
- percentage = (total_size - workqueue.size) * 100 / total_size
105
- if percentage >= last_percentage
106
- $stderr.print " #{percentage}% (#{total_size - workqueue.size}) "
107
- last_percentage += 10
108
- end
109
143
  end
110
144
 
111
145
  break if what.nil?
@@ -119,23 +153,56 @@ opts[:threads].times.map do
119
153
  end
120
154
  next if shound_skip.(name)
121
155
 
122
- source = what.decompile(decompile_options)
156
+ options = decompile_options.merge(
157
+ stat: {
158
+ total: 0,
159
+ success: 0,
160
+ partial: 0,
161
+ failed: 0,
162
+ }
163
+ )
164
+
165
+ source = what.decompile(options)
123
166
  next unless source
124
167
 
125
168
  text = source.to_text
126
169
 
127
170
  mutex.synchronize do
128
- $stderr.print "."
171
+ options[:stat].each do |facet, value|
172
+ stat[facet] += value
173
+ end
174
+
129
175
  roots[ns.to_s] ||= []
130
176
  roots[ns.to_s] << text
177
+
178
+ progress_thread.wakeup
131
179
  end
132
180
  end
133
181
  end
134
182
  end.each(&:join)
135
183
 
136
- $stderr.puts
184
+ end_time = Time.now
185
+
186
+ if stat[:total] > 0
187
+ $stderr.puts
137
188
 
138
- roots.values.flatten.each do |code|
139
- puts code
140
- puts
189
+ { "Decompiled" => :success,
190
+ "Partially decompiled" => :partial,
191
+ "Failed" => :failed,
192
+ }.each do |facet_name, facet|
193
+ $stderr.puts "#{facet_name.rjust(21)}: " \
194
+ "#{stat[facet]}/#{stat[:total]} " \
195
+ "(#{(stat[facet].to_f * 100 / stat[:total]).to_i}%)"
196
+ end
197
+ else
198
+ $stderr.puts "No methods were processed."
141
199
  end
200
+
201
+ $stderr.puts "Time taken: #{"%.2f" % (end_time - start_time)}s"
202
+
203
+ unless opts[:no_output]
204
+ roots.values.flatten.each do |code|
205
+ puts code.gsub(/ +$/, '')
206
+ puts
207
+ end
208
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+
5
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
6
+
7
+ require "furnace-avm2"
8
+
9
+ begin
10
+ gem "pry"
11
+ require "pry"
12
+ rescue LoadError
13
+ puts "$ gem install pry"
14
+ exit 1
15
+ end
16
+
17
+ include Furnace
18
+
19
+ def load_file(filename)
20
+ File.open(filename) do |file|
21
+ abc = AVM2::ABC::File.new
22
+ abc.read(file)
23
+ abc
24
+ end
25
+ end
26
+
27
+ # Interactive AVM2 console ready.
28
+ # Begin with:
29
+ # > abc = load_file("filename.abc")
30
+ # Records can be examined via #to_hash.
31
+
32
+ binding.pry
@@ -17,6 +17,6 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
- s.add_runtime_dependency "furnace", '>= 0.1.0'
20
+ s.add_runtime_dependency "furnace", '>= 0.1.1'
21
21
  s.add_runtime_dependency "trollop"
22
22
  end
@@ -10,18 +10,12 @@ require_relative "abc/primitives/record"
10
10
  require_relative "abc/primitives/opcode_sequence"
11
11
 
12
12
  require_relative "abc/opcodes/opcode"
13
- require_relative "abc/opcodes/contextual_opcode"
14
13
 
14
+ require_relative "abc/opcodes/contextual_opcode"
15
15
  require_relative "abc/opcodes/load_store_opcode"
16
- require_relative "abc/opcodes/arithmetic_opcode"
17
- require_relative "abc/opcodes/bitwise_opcode"
18
- require_relative "abc/opcodes/type_conversion_opcode"
19
16
  require_relative "abc/opcodes/push_literal_opcode"
20
17
  require_relative "abc/opcodes/control_transfer_opcode"
21
18
  require_relative "abc/opcodes/function_invocation_opcode"
22
- require_relative "abc/opcodes/function_return_opcode"
23
- require_relative "abc/opcodes/exception_opcode"
24
-
25
19
  require_relative "abc/opcodes/property_opcode"
26
20
 
27
21
  Dir[File.join(File.dirname(__FILE__), "abc", "opcodes", "*", "*.rb")].each do |file|
@@ -23,5 +23,70 @@ module Furnace::AVM2::ABC
23
23
  def root
24
24
  self
25
25
  end
26
+
27
+ def method_body_at(index)
28
+ @method_body_indexes[index]
29
+ end
30
+
31
+ def fix_names!
32
+ @name_set = Set.new(constant_pool.strings)
33
+
34
+ constant_pool.namespaces.each do |ns|
35
+ fix_name!(ns.name_idx, ns: true)
36
+ end
37
+
38
+ constant_pool.multinames.each do |multiname|
39
+ if [:QName, :QNameA,
40
+ :Multiname, :MultinameA,
41
+ :RTQName, :RTQMameA].include? multiname.kind
42
+ fix_name!(multiname.data.name_idx)
43
+ end
44
+ end
45
+ end
46
+
47
+ def fix_name!(name_idx, options={})
48
+ old_name = constant_pool.strings[name_idx - 1]
49
+ return if ["", "*"].include? old_name
50
+
51
+ fixed_name = sanitize_name(old_name, options)
52
+
53
+ if old_name != fixed_name
54
+ index = 0
55
+ indexed_name = fixed_name
56
+ while @name_set.include? indexed_name
57
+ indexed_name = "#{fixed_name}_i#{index}"
58
+ index += 1
59
+ end
60
+
61
+ @name_set.add indexed_name
62
+
63
+ constant_pool.strings[name_idx - 1] = indexed_name
64
+ end
65
+ end
66
+
67
+ def sanitize_name(name, options={})
68
+ if options[:ns]
69
+ return name if name.start_with? "http://"
70
+
71
+ name.split('.').map do |part|
72
+ part.gsub(/^[^a-zA-Z_$]+/, '').
73
+ gsub(/[^a-zA-Z_$0-9:]+/, '')
74
+ end.reject do |part|
75
+ part.empty?
76
+ end.join('.')
77
+ else
78
+ name.gsub(/^[^a-zA-Z_$]+/, '').
79
+ gsub(/[^a-zA-Z_$0-9:]+/, '')
80
+ end
81
+ end
82
+
83
+ protected
84
+
85
+ def after_read(io)
86
+ @method_body_indexes = {}
87
+ method_bodies.each do |body|
88
+ @method_body_indexes[body.method_idx] = body
89
+ end
90
+ end
26
91
  end
27
92
  end
@@ -63,21 +63,27 @@ module Furnace::AVM2::ABC
63
63
  end
64
64
 
65
65
  def collect_ns
66
- ns = []
67
- ns << super_name.ns if super_name
68
- ns += initializer.collect_ns if initializer
69
- interfaces.each { |iface| ns << iface.ns_set.ns[0] } # stupid avm2
70
- traits.each { |trait| ns += trait.collect_ns }
71
- klass.traits.each { |trait| ns += trait.collect_ns }
72
- ns
66
+ options = {
67
+ ns: Set.new([ name.ns ]),
68
+ names: { name.name => name.ns },
69
+ no_ns: Set.new,
70
+ }
71
+
72
+ super_name.collect_ns(options) if super_name
73
+ initializer.collect_ns(options) if initializer
74
+ interfaces.each { |iface| iface.collect_ns(options) } # stupid avm2
75
+ traits.each { |trait| trait.collect_ns(options) }
76
+ klass.traits.each { |trait| trait.collect_ns(options) }
77
+
78
+ options
73
79
  end
74
80
 
75
81
  def decompile(options={})
76
82
  Furnace::AVM2::Tokens::PackageToken.new(self,
77
- options.merge(
78
- ns: collect_ns,
79
- package_type: (interface? ? :interface : :class),
80
- package_name: name))
83
+ options.merge(collect_ns).merge(
84
+ package_type: (interface? ? :interface : :class),
85
+ package_name: name)
86
+ )
81
87
  end
82
88
  end
83
89
  end
@@ -1,9 +1,19 @@
1
1
  module Furnace::AVM2::ABC
2
2
  class MetadataInfo < Record
3
- vuint30 :name
3
+ const_ref :name, :string
4
4
 
5
- vuint30 :item_count, :value => lambda { item_keys.count }
6
- array :item_keys, :type => :vuint30, :initial_length => :item_count
7
- array :item_values, :type => :vuint30, :initial_length => :item_count
5
+ vuint30 :item_count, :value => lambda { item_keys.count }
6
+ const_array :item_keys, :string, :initial_length => :item_count
7
+ const_array :item_values, :string, :initial_length => :item_count
8
+
9
+ def to_hash
10
+ hash = {}
11
+
12
+ item_count.times do |n|
13
+ hash[item_keys[n]] = item_values[n]
14
+ end
15
+
16
+ hash
17
+ end
8
18
  end
9
19
  end
@@ -1,5 +1,7 @@
1
1
  module Furnace::AVM2::ABC
2
2
  class MethodBodyInfo < Record
3
+ include RecordWithTraits
4
+
3
5
  root_ref :method
4
6
  vuint30 :max_stack
5
7
  vuint30 :local_count
@@ -19,10 +21,10 @@ module Furnace::AVM2::ABC
19
21
  end
20
22
  end
21
23
 
22
- def code_to_ast(options={})
24
+ def code_to_ast(options={ eliminate_nops: true })
23
25
  pipeline = Furnace::Transform::Pipeline.new([
24
26
  Furnace::AVM2::Transform::ASTBuild.new(options),
25
- Furnace::AVM2::Transform::ASTNormalize.new
27
+ Furnace::AVM2::Transform::ASTNormalize.new(options)
26
28
  ])
27
29
 
28
30
  pipeline.run(code, self)
@@ -33,7 +35,7 @@ module Furnace::AVM2::ABC
33
35
  Furnace::AVM2::Transform::CFGBuild.new
34
36
  ])
35
37
 
36
- pipeline.run(*code_to_ast)
38
+ pipeline.run(*code_to_ast({}))
37
39
  end
38
40
 
39
41
  def code_to_nf
@@ -48,5 +50,11 @@ module Furnace::AVM2::ABC
48
50
  def decompile(options={})
49
51
  Furnace::AVM2::Decompiler.new(self, options).decompile
50
52
  end
53
+
54
+ def collect_ns(options)
55
+ code.each do |opcode|
56
+ opcode.collect_ns(options) if opcode.respond_to? :collect_ns
57
+ end
58
+ end
51
59
  end
52
60
  end
@@ -55,10 +55,9 @@ module Furnace::AVM2::ABC
55
55
  root.normalize_hierarchy!
56
56
  end
57
57
 
58
- def collect_ns
59
- ns = param_types.compact.map(&:collect_ns).reduce([], :+)
60
- ns += return_type.collect_ns if return_type
61
- ns
58
+ def collect_ns(options)
59
+ param_types.compact.each { |type| type.collect_ns(options) }
60
+ return_type.collect_ns(options) if return_type
62
61
  end
63
62
  end
64
63
  end
@@ -12,8 +12,9 @@ module Furnace::AVM2::ABC
12
12
  AST::Node.new(:generic, [ name.to_astlet, parameters.map(&:to_astlet) ])
13
13
  end
14
14
 
15
- def collect_ns
16
- [ *name.collect_ns, *parameters.map(&:collect_ns).reduce([], :+) ]
15
+ def collect_ns(options)
16
+ name.collect_ns(options)
17
+ parameters.each { |type| type.collect_ns(options) }
17
18
  end
18
19
  end
19
20
  end
@@ -11,8 +11,17 @@ module Furnace::AVM2::ABC
11
11
  AST::Node.new(:m, [ ns_set.to_astlet, name ])
12
12
  end
13
13
 
14
- def collect_ns
15
- ns_set.ns
14
+ def collect_ns(options)
15
+ ns = ns_set.ns[0]
16
+ return if options[:no_ns].include?(ns)
17
+
18
+ names = options[:names]
19
+ if names[name].nil?
20
+ options[:ns].add ns
21
+ names[name] = ns
22
+ elsif names[name] != ns
23
+ options[:no_ns].add ns
24
+ end
16
25
  end
17
26
 
18
27
  def context_size