furnace-avm2 0.9.0 → 0.9.1

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.
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