furnace-avm2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -0
- data/abcdump.abc +0 -0
- data/bin/furnace-avm2 +175 -0
- data/bin/furnace-avm2-benchmark +38 -0
- data/darkorbit.abc +0 -0
- data/furnace-avm2.gemspec +22 -0
- data/lib/avm2.rb +13 -0
- data/lib/avm2/abc.rb +65 -0
- data/lib/avm2/abc/metadata/const_pool_info.rb +18 -0
- data/lib/avm2/abc/metadata/exception_info.rb +29 -0
- data/lib/avm2/abc/metadata/file.rb +27 -0
- data/lib/avm2/abc/metadata/instance_info.rb +53 -0
- data/lib/avm2/abc/metadata/klass_info.rb +7 -0
- data/lib/avm2/abc/metadata/metadata_info.rb +9 -0
- data/lib/avm2/abc/metadata/method_body_info.rb +31 -0
- data/lib/avm2/abc/metadata/method_info.rb +57 -0
- data/lib/avm2/abc/metadata/multiname_info.rb +42 -0
- data/lib/avm2/abc/metadata/multiname_kind_genericname.rb +16 -0
- data/lib/avm2/abc/metadata/multiname_kind_multiname.rb +18 -0
- data/lib/avm2/abc/metadata/multiname_kind_multinamel.rb +17 -0
- data/lib/avm2/abc/metadata/multiname_kind_qname.rb +44 -0
- data/lib/avm2/abc/metadata/multiname_kind_rtqname.rb +17 -0
- data/lib/avm2/abc/metadata/multiname_kind_rtqnamel.rb +11 -0
- data/lib/avm2/abc/metadata/namespace_info.rb +22 -0
- data/lib/avm2/abc/metadata/ns_set_info.rb +13 -0
- data/lib/avm2/abc/metadata/option_detail.rb +26 -0
- data/lib/avm2/abc/metadata/option_info.rb +5 -0
- data/lib/avm2/abc/metadata/script_info.rb +7 -0
- data/lib/avm2/abc/metadata/trait_class.rb +9 -0
- data/lib/avm2/abc/metadata/trait_function.rb +9 -0
- data/lib/avm2/abc/metadata/trait_info.rb +55 -0
- data/lib/avm2/abc/metadata/trait_method.rb +12 -0
- data/lib/avm2/abc/metadata/trait_slot.rb +11 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_add.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_add_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_declocal.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_declocal_i.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_decrement.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_decrement_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_divide.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_equals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_greaterequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_greaterthan.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal_i.rb +18 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_increment.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_increment_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_lessequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_lessthan.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_modulo.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_multiply.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_multiply_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_negate.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_negate_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_not.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_strictequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_subtract.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_subtract_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitand.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitnot.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitor.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitxor.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_lshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_rshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_urshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/contextual_opcode.rb +32 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifeq.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iffalse.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifge.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifgt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifle.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iflt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifne.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnge.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifngt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnle.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnlt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifstricteq.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifstrictne.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iftrue.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_jump.rb +22 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_lookupswitch.rb +34 -0
- data/lib/avm2/abc/opcodes/control_transfer_opcode.rb +37 -0
- data/lib/avm2/abc/opcodes/exception/as3_newcatch.rb +16 -0
- data/lib/avm2/abc/opcodes/exception_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_call.rb +16 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callproperty.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callpropvoid.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callsuper.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callsupervoid.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation_opcode.rb +17 -0
- data/lib/avm2/abc/opcodes/function_return/as3_returnvalue.rb +8 -0
- data/lib/avm2/abc/opcodes/function_return/as3_returnvoid.rb +8 -0
- data/lib/avm2/abc/opcodes/function_return_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/generic/as3_astypelate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_checkfilter.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_dup.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_dxnslate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_escxattr.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_getglobalscope.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_getlex.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_getscopeobject.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_getslot.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_hasnext.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_hasnext2.rb +17 -0
- data/lib/avm2/abc/opcodes/generic/as3_in.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_instanceof.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_istypelate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_kill.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_label.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nextname.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nextvalue.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nop.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_pop.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_popscope.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_setslot.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_swap.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_throw.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_typeof.rb +8 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal.rb +15 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_0.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_1.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_2.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_3.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal.rb +15 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_0.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_1.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_2.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_3.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store_opcode.rb +18 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_construct.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_constructsuper.rb +16 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newactivation.rb +8 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newarray.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newclass.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newfunction.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newobject.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/opcode.rb +127 -0
- data/lib/avm2/abc/opcodes/property/as3_constructprop.rb +20 -0
- data/lib/avm2/abc/opcodes/property/as3_deleteproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_findproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_findpropstrict.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getdescendants.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getsuper.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_initproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_setproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_setsuper.rb +9 -0
- data/lib/avm2/abc/opcodes/property_opcode.rb +13 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushbyte.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushdouble.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushfalse.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushint.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushnan.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushnull.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushscope.rb +8 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushshort.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushstring.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushtrue.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushundefined.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushwith.rb +8 -0
- data/lib/avm2/abc/opcodes/push_literal_opcode.rb +18 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_applytype.rb +12 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce.rb +16 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_a.rb +8 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_b.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_s.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_d.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_i.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_o.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_s.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_u.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion_opcode.rb +4 -0
- data/lib/avm2/abc/primitives/opcode_sequence.rb +195 -0
- data/lib/avm2/abc/primitives/record.rb +132 -0
- data/lib/avm2/binary/choice_definition.rb +21 -0
- data/lib/avm2/binary/record.rb +469 -0
- data/lib/avm2/transform.rb +6 -0
- data/lib/avm2/transform/ast_build.rb +206 -0
- data/lib/avm2/transform/ast_normalize.rb +0 -0
- data/lib/avm2/version.rb +3 -0
- data/test/exception.abc +0 -0
- data/test/exception.as +29 -0
- data/test/literal.abc +0 -0
- data/test/literal.as +5 -0
- data/test/logic.abc +0 -0
- data/test/logic.as +23 -0
- data/test/loops.abc +0 -0
- data/test/loops.as +30 -0
- data/test/number.abc +0 -0
- data/test/number.as +14 -0
- data/test/switch.abc +0 -0
- data/test/switch.as +38 -0
- data/test/ternary.abc +0 -0
- data/test/ternary.as +22 -0
- metadata +579 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class OpcodeSequence < ::Array
|
3
|
+
attr_reader :root, :parent
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@root, @parent = options[:parent].root, options[:parent]
|
7
|
+
@pos_cache = {}
|
8
|
+
@opcode_cache = {}
|
9
|
+
|
10
|
+
@raw_code = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(io)
|
14
|
+
@raw_code = io.read(@parent.code_length)
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(io)
|
18
|
+
if @raw_code
|
19
|
+
io.write @raw_code
|
20
|
+
else
|
21
|
+
lookup!
|
22
|
+
|
23
|
+
each do |opcode|
|
24
|
+
opcode.write(io)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def each(&block)
|
30
|
+
parse if @raw_code
|
31
|
+
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# Offsets
|
36
|
+
|
37
|
+
def recache!
|
38
|
+
flush!
|
39
|
+
|
40
|
+
pos = 0
|
41
|
+
each do |opcode|
|
42
|
+
@pos_cache[pos] = opcode
|
43
|
+
@opcode_cache[opcode] = pos
|
44
|
+
|
45
|
+
pos += opcode.byte_length
|
46
|
+
end
|
47
|
+
|
48
|
+
lookup!
|
49
|
+
end
|
50
|
+
|
51
|
+
def flush!
|
52
|
+
@pos_cache = {}
|
53
|
+
@opcode_cache = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def opcode_at(position)
|
57
|
+
@pos_cache[position]
|
58
|
+
end
|
59
|
+
|
60
|
+
def offset_of(opcode)
|
61
|
+
@opcode_cache[opcode]
|
62
|
+
end
|
63
|
+
|
64
|
+
def byte_length
|
65
|
+
map(&:byte_length).reduce(0, :+)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Transformations
|
69
|
+
|
70
|
+
def disassemble
|
71
|
+
map(&:disassemble).join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_cfg
|
75
|
+
graph = CFG::Graph.new
|
76
|
+
|
77
|
+
targets = []
|
78
|
+
|
79
|
+
each do |opcode|
|
80
|
+
if opcode.is_a? ControlTransferOpcode
|
81
|
+
targets << opcode.target
|
82
|
+
elsif opcode.is_a? AS3LookupSwitch
|
83
|
+
targets << opcode.default_target
|
84
|
+
targets += opcode.case_targets
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if exceptions.any?
|
89
|
+
exception_node = CFG::Node.new(graph, :exception, [])
|
90
|
+
graph.nodes.add exception_node
|
91
|
+
|
92
|
+
exceptions.each do |exception|
|
93
|
+
targets << exception.target_offset
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
each do |opcode|
|
98
|
+
if targets.include? opcode
|
99
|
+
graph.transfer({ nil => opcode.offset })
|
100
|
+
end
|
101
|
+
|
102
|
+
graph.expand opcode.offset, opcode
|
103
|
+
|
104
|
+
if opcode.is_a? ControlTransferOpcode
|
105
|
+
if opcode.conditional
|
106
|
+
graph.transfer({ true => opcode.target.offset,
|
107
|
+
false => opcode.offset + opcode.byte_length })
|
108
|
+
else
|
109
|
+
graph.transfer({ nil => opcode.target.offset })
|
110
|
+
end
|
111
|
+
elsif opcode.is_a? AS3LookupSwitch
|
112
|
+
map = { nil => opcode.default_target.offset }
|
113
|
+
|
114
|
+
opcode.case_targets.each_with_index do |target, index|
|
115
|
+
map[index] = target.offset
|
116
|
+
end
|
117
|
+
|
118
|
+
graph.transfer map
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
graph.transfer({ })
|
123
|
+
|
124
|
+
exceptions.each do |exception|
|
125
|
+
graph.edges.add CFG::Edge.new(graph, nil, :exception, exception.target_offset)
|
126
|
+
end
|
127
|
+
|
128
|
+
graph
|
129
|
+
end
|
130
|
+
|
131
|
+
def eliminate_dead!
|
132
|
+
cfg = build_cfg
|
133
|
+
dead_opcodes = []
|
134
|
+
|
135
|
+
cfg.nodes.each do |node|
|
136
|
+
if node.label != 0 && node.entering_edges.count == 0
|
137
|
+
dead_opcodes.concat node.operations
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
dead_opcodes.each do |opcode|
|
142
|
+
delete opcode
|
143
|
+
end
|
144
|
+
|
145
|
+
recache!
|
146
|
+
|
147
|
+
dead_opcodes.any?
|
148
|
+
end
|
149
|
+
|
150
|
+
protected
|
151
|
+
|
152
|
+
def parse
|
153
|
+
sub_io = StringIO.new(@raw_code)
|
154
|
+
map = Opcode::MAP
|
155
|
+
|
156
|
+
until sub_io.eof?
|
157
|
+
instruction = sub_io.read(1).unpack("C").at(0)
|
158
|
+
|
159
|
+
opcode = map[instruction]
|
160
|
+
if opcode.nil?
|
161
|
+
raise "Unknown opcode 0x#{instruction.to_s(16)}"
|
162
|
+
end
|
163
|
+
|
164
|
+
element = opcode.new(self)
|
165
|
+
|
166
|
+
@pos_cache[sub_io.pos - 1] = element
|
167
|
+
@opcode_cache[element] = sub_io.pos - 1
|
168
|
+
|
169
|
+
element.read(sub_io)
|
170
|
+
|
171
|
+
self << element
|
172
|
+
end
|
173
|
+
|
174
|
+
@raw_code = nil
|
175
|
+
|
176
|
+
each do |element|
|
177
|
+
element.resolve! if element.respond_to? :resolve!
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def lookup!
|
182
|
+
each do |element|
|
183
|
+
element.lookup! if element.respond_to? :lookup!
|
184
|
+
end
|
185
|
+
|
186
|
+
exceptions.each do |exception|
|
187
|
+
exception.lookup!
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def exceptions
|
192
|
+
@parent.exceptions
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class Record < AVM2::Binary::Record
|
3
|
+
def self.abc_array_of(name, type, options={})
|
4
|
+
field_size, field_array = :"#{name}_count", options.delete(:plural) || :"#{name}s"
|
5
|
+
klass = options.delete(:class)
|
6
|
+
|
7
|
+
vuint30 field_size, { :value => lambda { send(field_array).count } }.merge(options)
|
8
|
+
array field_array, { :type => type, :initial_length => field_size,
|
9
|
+
:options => { :class => klass } }.merge(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Pools
|
13
|
+
|
14
|
+
def self.pool_ref(pool, name, type=name, options={})
|
15
|
+
field, array = :"#{name}_idx", options.delete(:plural) || :"#{type}s"
|
16
|
+
|
17
|
+
vuint30 field, options
|
18
|
+
|
19
|
+
if pool == :root
|
20
|
+
define_method(name) do
|
21
|
+
root.send(array)[send(field)]
|
22
|
+
end
|
23
|
+
elsif pool == :const
|
24
|
+
define_method(name) do
|
25
|
+
index = send(field)
|
26
|
+
if index == 0
|
27
|
+
nil
|
28
|
+
else
|
29
|
+
root.constant_pool.send(array)[index - 1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.pool_array(pool, name, type, options={})
|
36
|
+
field, type_plural = :"#{name}_raw", options.delete(:plural) || :"#{type}s"
|
37
|
+
|
38
|
+
array field, { :type => :vuint30 }.merge(options)
|
39
|
+
|
40
|
+
if pool == :root
|
41
|
+
define_method(name) do
|
42
|
+
send(field).map do |element|
|
43
|
+
root.send(type_plural)[element]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
elsif pool == :const
|
47
|
+
define_method(name) do
|
48
|
+
send(field).map do |element|
|
49
|
+
if element == 0
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
root.constant_pool.send(type_plural)[element - 1]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.pool_array_of(pool, name, type, options={})
|
60
|
+
field_size, field_array = :"#{name}_count", options.delete(:plural) || :"#{name}s"
|
61
|
+
|
62
|
+
vuint30 field_size, { :value => lambda { send(field_array).count } }.merge(options)
|
63
|
+
pool_array pool, field_array, type, { :initial_length => field_size }.merge(options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Pool references
|
67
|
+
|
68
|
+
[:root, :const].each do |pool|
|
69
|
+
[:ref, :array, :array_of].each do |method|
|
70
|
+
define_singleton_method(:"#{pool}_#{method}") do |*args|
|
71
|
+
send(:"pool_#{method}", pool, *args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Xlat
|
77
|
+
|
78
|
+
def self.xlat_direct
|
79
|
+
@xlat_direct ||= const_get(:XlatTable).invert
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.xlat_inverse
|
83
|
+
@xlat_inverse ||= const_get(:XlatTable)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.xlat_field(name)
|
87
|
+
define_method(:"#{name}") do
|
88
|
+
value = instance_variable_get :"@#{name}_raw"
|
89
|
+
|
90
|
+
unless self.class.xlat_direct.has_key? value
|
91
|
+
raise ArgumentError, "Unknown xlat value #{value} for #{self.class}"
|
92
|
+
end
|
93
|
+
|
94
|
+
self.class.xlat_direct[value]
|
95
|
+
end
|
96
|
+
|
97
|
+
define_method(:"#{name}=") do |new_value|
|
98
|
+
unless self.class.xlat_inverse.has_key? new_value
|
99
|
+
raise ArgumentError, "Unknown xlat identifier #{new_value} for #{self.class}"
|
100
|
+
end
|
101
|
+
|
102
|
+
instance_variable_set :"@#{name}_raw", self.class.xlat_inverse[new_value]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Flags
|
107
|
+
|
108
|
+
def self.flag(name, field, constant)
|
109
|
+
define_method(:"#{name}?") do
|
110
|
+
instance_variable_get(:"@#{field}") & constant != 0
|
111
|
+
end
|
112
|
+
|
113
|
+
define_method(:"#{name}=") do |is_set|
|
114
|
+
flags = instance_variable_get(:"@#{field}")
|
115
|
+
|
116
|
+
if is_set
|
117
|
+
instance_variable_set(:"@#{field}", flags | constant)
|
118
|
+
else
|
119
|
+
instance_variable_set(:"@#{field}", flags & ~constant)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Subsetting
|
125
|
+
|
126
|
+
def self.subset(name, array, selector)
|
127
|
+
define_method(:"#{name}") do
|
128
|
+
send(array).select &selector
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|