ruby_android_apk 0.7.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,174 @@
1
+ require 'rexml/document'
2
+ require 'stringio'
3
+
4
+
5
+ module Android
6
+ # binary AXML parser
7
+ # @see https://android.googlesource.com/platform/frameworks/base.git Android OS frameworks source
8
+ # @note
9
+ # refer to Android OS framework code:
10
+ #
11
+ # /frameworks/base/include/androidfw/ResourceTypes.h,
12
+ #
13
+ # /frameworks/base/libs/androidfw/ResourceTypes.cpp
14
+ class AXMLParser
15
+ def self.axml?(data)
16
+ (data[0..3] == "\x03\x00\x08\x00")
17
+ end
18
+
19
+ # axml parse error
20
+ class ReadError < StandardError; end
21
+
22
+ TAG_START_DOC = 0x00100100
23
+ TAG_END_DOC = 0x00100101
24
+ TAG_START = 0x00100102
25
+ TAG_END = 0x00100103
26
+ TAG_TEXT = 0x00100104
27
+ TAG_CDSECT = 0x00100105
28
+ TAG_ENTITY_REF= 0x00100106
29
+
30
+ VAL_TYPE_NULL =0
31
+ VAL_TYPE_REFERENCE =1
32
+ VAL_TYPE_ATTRIBUTE =2
33
+ VAL_TYPE_STRING =3
34
+ VAL_TYPE_FLOAT =4
35
+ VAL_TYPE_DIMENSION =5
36
+ VAL_TYPE_FRACTION =6
37
+ VAL_TYPE_INT_DEC =16
38
+ VAL_TYPE_INT_HEX =17
39
+ VAL_TYPE_INT_BOOLEAN =18
40
+ VAL_TYPE_INT_COLOR_ARGB8 =28
41
+ VAL_TYPE_INT_COLOR_RGB8 =29
42
+ VAL_TYPE_INT_COLOR_ARGB4 =30
43
+ VAL_TYPE_INT_COLOR_RGB4 =31
44
+
45
+ # @return [Array<String>] strings defined in axml
46
+ attr_reader :strings
47
+
48
+ # @param [String] axml binary xml data
49
+ def initialize(axml)
50
+ @io = StringIO.new(axml, "rb")
51
+ @strings = []
52
+ end
53
+
54
+ # parse binary xml
55
+ # @return [REXML::Document]
56
+ def parse
57
+ @doc = REXML::Document.new
58
+ @doc << REXML::XMLDecl.new
59
+
60
+ @num_str = word(4*4)
61
+ @xml_offset = word(3*4)
62
+
63
+ @parents = [@doc]
64
+ @ns = []
65
+ parse_strings
66
+ parse_tags
67
+ @doc
68
+ end
69
+
70
+
71
+ # read one word(4byte) as integer
72
+ # @param [Integer] offset offset from top position. current position is used if ofset is nil
73
+ # @return [Integer] little endian word value
74
+ def word(offset=nil)
75
+ @io.pos = offset unless offset.nil?
76
+ @io.read(4).unpack("V")[0]
77
+ end
78
+
79
+ # read 2byte as short integer
80
+ # @param [Integer] offset offset from top position. current position is used if ofset is nil
81
+ # @return [Integer] little endian unsign short value
82
+ def short(offset)
83
+ @io.pos = offset unless offset.nil?
84
+ @io.read(2).unpack("v")[0]
85
+ end
86
+
87
+ # relace string table parser
88
+ def parse_strings
89
+ strpool = Resource::ResStringPool.new(@io.string, 8) # ugh!
90
+ @strings = strpool.strings
91
+ end
92
+
93
+ # parse tag
94
+ def parse_tags
95
+ # skip until START_TAG
96
+ pos = @xml_offset
97
+ pos += 4 until (word(pos) == TAG_START) #ugh!
98
+ @io.pos -= 4
99
+
100
+ # read tags
101
+ #puts "start tag parse: %d(%#x)" % [@io.pos, @io.pos]
102
+ until @io.eof?
103
+ last_pos = @io.pos
104
+ tag, tag1, line, tag3, ns_id, name_id = @io.read(4*6).unpack("V*")
105
+ case tag
106
+ when TAG_START
107
+ tag6, num_attrs, tag8 = @io.read(4*3).unpack("V*")
108
+ elem = REXML::Element.new(@strings[name_id])
109
+ #puts "start tag %d(%#x): #{@strings[name_id]} attrs:#{num_attrs}" % [last_pos, last_pos]
110
+ @parents.last.add_element elem
111
+ num_attrs.times do
112
+ key, val = parse_attribute
113
+ elem.add_attribute(key, val)
114
+ end
115
+ @parents.push elem
116
+ when TAG_END
117
+ @parents.pop
118
+ when TAG_END_DOC
119
+ #fix multi tag_end_doc
120
+ #break
121
+ when TAG_TEXT
122
+ text = REXML::Text.new(@strings[ns_id])
123
+ @parents.last.text = text
124
+ dummy = @io.read(4*1).unpack("V*") # skip 4bytes
125
+ when TAG_START_DOC, TAG_CDSECT, TAG_ENTITY_REF
126
+ # not implemented yet.
127
+ else
128
+ raise ReadError, "pos=%d(%#x)[tag:%#x]" % [last_pos, last_pos, tag]
129
+ end
130
+ end
131
+ end
132
+
133
+ # parse attribute of a element
134
+ def parse_attribute
135
+ ns_id, name_id, val_str_id, flags, val = @io.read(4*5).unpack("V*")
136
+ key = @strings[name_id]
137
+ unless ns_id == 0xFFFFFFFF
138
+ ns = @strings[ns_id]
139
+ prefix = ns.sub(/.*\//,'')
140
+ unless @ns.include? ns
141
+ @ns << ns
142
+ @doc.root.add_namespace(prefix, ns)
143
+ end
144
+ key = "#{prefix}:#{key}"
145
+ end
146
+ value = convert_value(val_str_id, flags, val)
147
+ return key, value
148
+ end
149
+
150
+
151
+ def convert_value(val_str_id, flags, val)
152
+ unless val_str_id == 0xFFFFFFFF
153
+ value = @strings[val_str_id]
154
+ else
155
+ type = flags >> 24
156
+ case type
157
+ when VAL_TYPE_NULL
158
+ value = nil
159
+ when VAL_TYPE_REFERENCE
160
+ value = "@%#x" % val # refered resource id.
161
+ when VAL_TYPE_INT_DEC
162
+ value = val
163
+ when VAL_TYPE_INT_HEX
164
+ value = "%#x" % val
165
+ when VAL_TYPE_INT_BOOLEAN
166
+ value = ((val == 0xFFFFFFFF) || (val==1)) ? true : false
167
+ else
168
+ value = "[%#x, flag=%#x]" % [val, flags]
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ end
@@ -0,0 +1,92 @@
1
+ require_relative 'dex/dex_object'
2
+ require_relative 'dex/info'
3
+ require_relative 'dex/access_flag'
4
+ require_relative 'dex/utils'
5
+
6
+ module Android
7
+ # parsed dex object
8
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
9
+ # @attr_reader strings [Array<String>] strings in dex file.
10
+ class Dex
11
+ # @return [Dex::Header] dex header information
12
+ attr_reader :header
13
+ alias :h :header
14
+
15
+ # @return [String] dex binary data
16
+ attr_reader :data
17
+ # @return [Array<Dex::ClassInfo>] array of class information
18
+ attr_reader :classes
19
+
20
+ attr_reader :field_ids, :method_ids, :proto_ids
21
+ # @param [String] data dex binary data
22
+ def initialize(data)
23
+ @data = data
24
+ @data.force_encoding(Encoding::ASCII_8BIT)
25
+ @classes = []
26
+ parse()
27
+ end
28
+
29
+ def strings
30
+ @strings ||= @string_data_items.map{|item| item.to_s }
31
+ end
32
+
33
+ def inspect
34
+ "<Android::Dex @classes => #{@classes.size}, datasize => #{@data.size}>"
35
+ end
36
+
37
+
38
+ # @private
39
+ TYPE_DESCRIPTOR = {
40
+ 'V' => 'void',
41
+ 'Z' => 'boolean',
42
+ 'B' => 'byte',
43
+ 'S' => 'short',
44
+ 'C' => 'short',
45
+ 'I' => 'int',
46
+ 'J' => 'long',
47
+ 'F' => 'float',
48
+ 'D' => 'double'
49
+ }
50
+
51
+
52
+ def type_resolve(typeid)
53
+ type = strings[@type_ids[typeid]]
54
+ if type.start_with? '['
55
+ type = type[1..type.size]
56
+ return TYPE_DESCRIPTOR.fetch(type, type) + "[]" # TODO: recursive
57
+ else
58
+ return TYPE_DESCRIPTOR.fetch(type, type)
59
+ end
60
+ end
61
+
62
+
63
+ private
64
+ def parse
65
+ @header = DexObject::Header.new(@data)
66
+ @map_list = DexObject::MapList.new(@data, h[:map_off])
67
+
68
+ # parse strings
69
+ @string_ids = DexObject::StringIdItem.new(@data, h[:string_ids_off], h[:string_ids_size])
70
+ @string_data_items = []
71
+ @string_ids[:string_data_off].each { |off| @string_data_items << DexObject::StringDataItem.new(@data, off) }
72
+
73
+ @type_ids = DexObject::TypeIdItem.new(@data, h[:type_ids_off], h[:type_ids_size])
74
+ @proto_ids = ids_list_array(DexObject::ProtoIdItem, h[:proto_ids_off], h[:proto_ids_size])
75
+ @field_ids = ids_list_array(DexObject::FieldIdItem, h[:field_ids_off], h[:field_ids_size])
76
+ @method_ids = ids_list_array(DexObject::MethodIdItem, h[:method_ids_off], h[:method_ids_size])
77
+ @class_defs = ids_list_array(DexObject::ClassDefItem, h[:class_defs_off], h[:class_defs_size])
78
+
79
+ @classes = []
80
+ @class_defs.each do |cls_def|
81
+ @classes << ClassInfo.new(cls_def, self)
82
+ end
83
+ end
84
+
85
+ def ids_list_array(cls, offset, size)
86
+ ret_array = []
87
+ size.times { |i| ret_array << cls.new(@data, offset + cls.size * i) }
88
+ ret_array
89
+ end
90
+ end
91
+ end
92
+
@@ -0,0 +1,74 @@
1
+
2
+ module Android
3
+ class Dex
4
+ # access flag object
5
+ class AccessFlag
6
+ # @return [Integer] flag value
7
+ attr_reader :flag
8
+ def initialize(flag)
9
+ @flag = flag
10
+ end
11
+ end
12
+
13
+ # access flag object for class in dex
14
+ class ClassAccessFlag < AccessFlag
15
+ ACCESSORS = [
16
+ {value:0x1, name:'public'},
17
+ {value:0x2, name:'private'},
18
+ {value:0x4, name:'protected'},
19
+ {value:0x8, name:'static'},
20
+ {value:0x10, name:'final'},
21
+ {value:0x20, name:'synchronized'},
22
+ {value:0x40, name:'volatile'},
23
+ {value:0x80, name:'transient'},
24
+ {value:0x100, name:'native'},
25
+ {value:0x200, name:'interface'},
26
+ {value:0x400, name:'abstract'},
27
+ {value:0x800, name:'strict'},
28
+ {value:0x1000, name:'synthetic'},
29
+ {value:0x2000, name:'annotation'},
30
+ {value:0x4000, name:'enum'},
31
+ #{value:0x8000, name:'unused'},
32
+ {value:0x10000, name:'constructor'},
33
+ {value:0x20000, name:'declared-synchronized'},
34
+ ]
35
+
36
+ # convert access flag to string
37
+ # @return [String]
38
+ def to_s
39
+ ACCESSORS.select{|e| ((e[:value] & @flag) != 0) }.map{|e| e[:name] }.join(' ')
40
+ end
41
+ end
42
+
43
+ # access flag object for method in dex
44
+ class MethodAccessFlag < AccessFlag
45
+ ACCESSORS = [
46
+ {value: 0x1, name:'public'},
47
+ {value: 0x2, name:'private'},
48
+ {value: 0x4, name:'protected'},
49
+ {value: 0x8, name:'static'},
50
+ {value: 0x10, name:'final'},
51
+ {value: 0x20, name:'synchronized'},
52
+ {value: 0x40, name:'bridge'},
53
+ {value: 0x80, name:'varargs'},
54
+ {value: 0x100, name:'native'},
55
+ {value: 0x200, name:'interface'},
56
+ {value: 0x400, name:'abstract'},
57
+ {value: 0x800, name:'strict'},
58
+ {value: 0x1000, name:'synthetic'},
59
+ {value: 0x2000, name:'annotation'},
60
+ {value: 0x4000, name:'enum'},
61
+ #{value: 0x8000, name:'unused'},
62
+ {value: 0x10000, name:'constructor'},
63
+ {value: 0x20000, name:'declared-synchronized'},
64
+ ]
65
+ # convert access flag to string
66
+ # @return [String]
67
+ def to_s
68
+ ACCESSORS.select{|e| ((e[:value] & @flag) != 0) }.map{|e| e[:name] }.join(' ')
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+
@@ -0,0 +1,475 @@
1
+
2
+ module Android
3
+ class Dex
4
+ # parsing dex object
5
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
6
+ class DexObject
7
+ # @return [Integer] object size
8
+ attr_reader :size
9
+
10
+ def initialize(data, offset)
11
+ @data = data
12
+ @offset = offset
13
+
14
+ @params = {}
15
+ @parsing_off = 0 # parsing offset
16
+ parse()
17
+ @size = @parsing_off
18
+ end
19
+
20
+ # returns symbol keys
21
+ # @return [Array<Symbol>] header key
22
+ def symbols
23
+ @params.keys
24
+ end
25
+
26
+ # @param [Symbol] sym should be included in #symbols
27
+ # @return [Object] dex header value which is related with sym
28
+ def [](sym)
29
+ @params[sym.to_sym]
30
+ end
31
+
32
+ # @return [String]
33
+ def inspect
34
+ str = "<#{self.class}\n"
35
+ @params.each do |key,val|
36
+ str.concat " #{key}: #{val}\n"
37
+ end
38
+ str.concat '>'
39
+ end
40
+
41
+ private
42
+ def parse
43
+ raise 'this method should be overloaded.'
44
+ end
45
+
46
+ def read_value(type)
47
+ types = {
48
+ :byte => [1, 'c'],
49
+ :ubyte => [1, 'C'],
50
+ :short => [2, 's'], #ugh!:depend on machine endian
51
+ :ushort => [2, 'v'],
52
+ :int => [4, 'i'], #ugh!:depend on machine endian
53
+ :uint => [4, 'V'],
54
+ :long => [8, 'q'],
55
+ :ulong => [8, 'Q'],
56
+ }
57
+ len, pack_str = types.fetch(type)
58
+ value = @data[@offset+@parsing_off, len].unpack(pack_str)[0]
59
+ @parsing_off += len
60
+ return value
61
+ end
62
+
63
+ # read short int from data buffer
64
+ # @return [Integer] short value
65
+ def read_sleb
66
+ value, len = Dex::sleb128(@data, @offset + @parsing_off)
67
+ @parsing_off += len
68
+ value
69
+ end
70
+ # read integer from data buffer
71
+ # @return [Integer] integer value
72
+ def read_uleb
73
+ value, len = Dex::uleb128(@data, @offset + @parsing_off)
74
+ @parsing_off += len
75
+ value
76
+ end
77
+ # read integer from data buffer and plus 1
78
+ # @return [Integer] integer value
79
+ def read_uleb128p1
80
+ value, len = Dex::uleb128p1(@data, @offset + @parsing_off)
81
+ @parsing_off += len
82
+ value
83
+ end
84
+ # read various values from data buffer as array
85
+ # @param [Symbol] type
86
+ # @param [Integer] size num of data
87
+ # @return [Array] value array
88
+ def read_value_array(type, size)
89
+ ret_array = []
90
+ size.times { ret_array << read_value(type) }
91
+ ret_array
92
+ end
93
+ # read class values from data buffer as array
94
+ # @param [Class] cls target class
95
+ # @param [Integer] size num of data
96
+ # @return [Array<cls>] object array
97
+ def read_class_array(cls, size)
98
+ ret_array = []
99
+ size.times do
100
+ item = cls.new(@data, @offset + @parsing_off)
101
+ ret_array << item
102
+ @parsing_off += item.size
103
+ end
104
+ ret_array
105
+ end
106
+
107
+ public
108
+ # header_item
109
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
110
+ class Header < DexObject
111
+ def initialize(data)
112
+ super(data, 0)
113
+ end
114
+
115
+ private
116
+ def parse
117
+ @params[:magic] = @data[0, 8]
118
+ @parsing_off += 8
119
+ @params[:checksum] = read_value(:uint)
120
+ @params[:signature] = @data[12, 20]
121
+ @parsing_off += 20
122
+ [
123
+ :file_size, :header_size, :endian_tag, :link_size, :link_off, :map_off,
124
+ :string_ids_size, :string_ids_off, :type_ids_size, :type_ids_off,
125
+ :proto_ids_size, :proto_ids_off, :field_ids_size, :field_ids_off,
126
+ :method_ids_size, :method_ids_off, :class_defs_size, :class_defs_off,
127
+ :data_size, :data_off
128
+ ].each do |key|
129
+ @params[key] = read_value(:uint)
130
+ end
131
+ end
132
+ end
133
+
134
+ # map_list
135
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
136
+ class MapList < DexObject
137
+ private
138
+ def parse
139
+ @params[:size] = read_value(:uint)
140
+ @params[:list] = read_class_array(MapItem, @params[:size])
141
+ end
142
+ end
143
+
144
+ # map_item
145
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
146
+ class MapItem < DexObject
147
+ private
148
+ def parse
149
+ @params[:type] = read_value(:short)
150
+ @params[:unused] = read_value(:short)
151
+ @params[:size] = read_value(:uint)
152
+ @params[:offset] = read_value(:uint)
153
+ end
154
+ end
155
+
156
+ # id_list
157
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
158
+ class IdsList < DexObject
159
+ attr_reader :ids_size
160
+ def initialize(data, off, ids_size)
161
+ @ids_size = ids_size
162
+ super(data, off)
163
+ end
164
+ end
165
+
166
+ # string_id_item
167
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
168
+ class StringIdItem < IdsList
169
+ private
170
+ def parse
171
+ @params[:string_data_off] = read_value_array(:uint, @ids_size)
172
+ end
173
+ end
174
+
175
+ # string_data_item
176
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
177
+ class StringDataItem < DexObject
178
+ def to_s
179
+ @params[:data]
180
+ end
181
+ private
182
+ def mutf8_to_utf8(data, off, ulen)
183
+ mi = 0 # index of mutf8 data
184
+ codepoints = []
185
+ while ulen > 0 do
186
+ b0 = data[off + mi].ord
187
+ bu = (b0 & 0xf0) # b0's upper nibble
188
+ if (b0 & 0x80) == 0 # single byte encoding (0b0xxx_xxxx)
189
+ c = b0
190
+ mi += 1
191
+ ulen -= 1
192
+ elsif bu == 0xc0 || bu == 0xd0 # two-byte encoding (0b110x_xxxx)
193
+ b1 = data[off + mi + 1].ord
194
+ c = (b0 & 0x1f) << 6 | (b1 & 0x3f)
195
+ mi += 2
196
+ ulen -= 1
197
+ elsif bu == 0xe0 # three-byte encoding (0b1110_xxxx)
198
+ b1 = data[off + mi + 1].ord
199
+ b2 = data[off + mi + 2].ord
200
+ c = (b0 & 0x0f) << 12 | (b1 & 0x3f) << 6 | (b2 & 0x3f)
201
+ mi += 3
202
+ ulen -= 1
203
+ if 0xD800 <= c && c <= 0xDBFF # this must be a surrogate pair
204
+ b4 = data[off + mi + 1].ord
205
+ b5 = data[off + mi + 2].ord
206
+ c = ((b1 & 0x0f) + 1) << 16 | (b2 & 0x3f) << 10 | (b4 & 0x0f) << 6 | (b5 & 0x3f)
207
+ mi += 3
208
+ ulen -= 1
209
+ end
210
+ else
211
+ STDERR.puts "unsupported byte: 0x#{'%02X' % b0} @#{mi}"
212
+ c = 0
213
+ mi += 1
214
+ next
215
+ end
216
+ if c != 0
217
+ codepoints << c
218
+ end
219
+ end
220
+ codepoints.pack("U*")
221
+ end
222
+ def parse
223
+ @params[:utf16_size] = read_uleb
224
+ @params[:data] = mutf8_to_utf8(@data, @offset + @parsing_off, @params[:utf16_size])
225
+ end
226
+ end
227
+
228
+ # type_id_item
229
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
230
+ class TypeIdItem < IdsList
231
+ def [](idx)
232
+ raise ArgumentError if idx >= @params[:descriptor_idx].size or idx < 0
233
+ @params[:descriptor_idx][idx]
234
+ end
235
+
236
+ private
237
+ def parse
238
+ @params[:descriptor_idx] = read_value_array(:uint, @ids_size)
239
+ end
240
+ end
241
+
242
+ # proto_id_item
243
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
244
+ class ProtoIdItem < DexObject
245
+ # return parse data size
246
+ # @return bytes
247
+ # @note this method for DexObject#read_class_array (private method)
248
+ def self.size
249
+ 4 * 3
250
+ end
251
+ private
252
+ def parse
253
+ @params[:shorty_idx] = read_value(:uint)
254
+ @params[:return_type_idx] = read_value(:uint)
255
+ @params[:parameters_off] = read_value(:uint)
256
+ end
257
+ end
258
+
259
+ # field_id_item
260
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
261
+ class FieldIdItem < DexObject
262
+ # return parse data size
263
+ # @return bytes
264
+ # @note this method for DexObject#read_class_array (private method)
265
+ def self.size
266
+ 2 * 2 + 4
267
+ end
268
+ private
269
+ def parse
270
+ @params[:class_idx] = read_value(:ushort)
271
+ @params[:type_idx] = read_value(:ushort)
272
+ @params[:name_idx] = read_value(:uint)
273
+ end
274
+ end
275
+
276
+ # method_id_item
277
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
278
+ class MethodIdItem < DexObject
279
+ # return parse data size
280
+ # @return bytes
281
+ # @note this method for DexObject#read_class_array (private method)
282
+ def self.size
283
+ 2 * 2 + 4
284
+ end
285
+ def parse
286
+ @params[:class_idx] = read_value(:ushort)
287
+ @params[:proto_idx] = read_value(:ushort)
288
+ @params[:name_idx] = read_value(:uint)
289
+ end
290
+ end
291
+
292
+ # class_def_item
293
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
294
+ # @!attribute [r] class_data_item
295
+ # @return [ClassDataItem] class_data_item of this class
296
+ class ClassDefItem < DexObject
297
+ # @return [Integer] bytes
298
+ def self.size
299
+ 4 * 8
300
+ end
301
+
302
+ def class_data_item
303
+ # description of class_data_off of class_def_item.
304
+ # offset from the start of the file to the associated class data
305
+ # for this item, or 0 if there is no class data for this class.
306
+ if @params[:class_data_off] != 0
307
+ @class_data_item ||= ClassDataItem.new(@data, @params[:class_data_off])
308
+ else
309
+ nil
310
+ end
311
+ end
312
+
313
+ private
314
+ def parse
315
+ @params[:class_idx] = read_value(:uint)
316
+ @params[:access_flags] = read_value(:uint)
317
+ @params[:superclass_idx] = read_value(:uint)
318
+ @params[:interfaces_off] = read_value(:uint)
319
+ @params[:source_file_idx] = read_value(:uint)
320
+ @params[:annotations_off] = read_value(:uint)
321
+ @params[:class_data_off] = read_value(:uint)
322
+ @params[:static_values_off] = read_value(:uint) # TODO: not implemented encoded_array_item
323
+ end
324
+ end
325
+
326
+ # class_data_item
327
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
328
+ class ClassDataItem < DexObject
329
+ private
330
+ def parse
331
+ @params[:static_fields_size] = read_uleb
332
+ @params[:instance_fields_size] = read_uleb
333
+ @params[:direct_methods_size] = read_uleb
334
+ @params[:virtual_methods_size] = read_uleb
335
+ @params[:static_fields] = read_class_array(EncodedField, @params[:static_fields_size])
336
+ @params[:instance_fields] = read_class_array(EncodedField, @params[:instance_fields_size])
337
+ @params[:direct_methods] = read_class_array(EncodedMethod, @params[:direct_methods_size])
338
+ @params[:virtual_methods] = read_class_array(EncodedMethod, @params[:virtual_methods_size])
339
+ end
340
+ end
341
+
342
+ # encoded_field
343
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
344
+ class EncodedField < DexObject
345
+ private
346
+ def parse
347
+ @params[:field_idx_diff] = read_uleb
348
+ @params[:access_flags] = read_uleb
349
+ end
350
+ end
351
+
352
+ # encoded_method
353
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
354
+ # @!attribute [r] code_item
355
+ # @return [CodeItem] code_item of the method
356
+ class EncodedMethod < DexObject
357
+ def code_item
358
+ # description of code_off in code_data_item.
359
+ # offset from the start of the file to the code structure for this method,
360
+ # or 0 if this method is either abstract or native.
361
+ unless @params[:code_off] == 0
362
+ @code_item ||= CodeItem.new(@data, @params[:code_off])
363
+ else
364
+ nil
365
+ end
366
+ end
367
+
368
+ private
369
+ def parse
370
+ @params[:method_idx_diff] = read_uleb
371
+ @params[:access_flags] = read_uleb
372
+ @params[:code_off] = read_uleb
373
+ end
374
+ end
375
+
376
+
377
+ # type_list
378
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
379
+ class TypeList < DexObject
380
+ private
381
+ def parse
382
+ @params[:size] = read_value(:uint)
383
+ @params[:list] = read_value_array(:ushort, @params[:size])
384
+ end
385
+ end
386
+
387
+ # code_item
388
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
389
+ # @!attribute [r] debug_info_item
390
+ # @return [DebugInfoItem] debug_info_item of this code
391
+ class CodeItem < DexObject
392
+ def debug_info_item
393
+ unless @params[:debug_info_off] == 0
394
+ @debug_info_item ||= DebugInfoItem.new(@data, @params[:debug_info_off])
395
+ else
396
+ nil
397
+ end
398
+ end
399
+
400
+ private
401
+ def parse
402
+ @params[:registers_size] = read_value(:ushort)
403
+ @params[:ins_size] = read_value(:ushort)
404
+ @params[:outs_size] = read_value(:ushort)
405
+ @params[:tries_size] = read_value(:ushort)
406
+ @params[:debug_info_off] = read_value(:uint)
407
+ @params[:insns_size] = read_value(:uint) # size of the instructions list
408
+ @params[:insns] = read_value_array(:ushort, @params[:insns_size])
409
+ read_value(:ushort) if ((@params[:insns_size] % 2) == 1) # for four-byte aligned
410
+ if @params[:tries_size] > 0
411
+ # This element is only present if tries_size is non-zero.
412
+ @params[:tries] = read_class_array(TryItem, @params[:tries_size])
413
+ # This element is only present if tries_size is non-zero.
414
+ @params[:handlers] = EncodedCatchHandlerList.new(@data, @offset + @parsing_off)
415
+ @parsing_off += @params[:handlers].size
416
+ end
417
+ end
418
+ end
419
+
420
+ # try_item
421
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
422
+ class TryItem < DexObject
423
+ private
424
+ def parse
425
+ @params[:start_addr] = read_value(:uint)
426
+ @params[:insn_count] = read_value(:ushort)
427
+ @params[:handler_off] = read_value(:ushort)
428
+ end
429
+ end
430
+
431
+ # encoded_catch_handler_list
432
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
433
+ class EncodedCatchHandlerList < DexObject
434
+ private
435
+ def parse
436
+ @params[:size] = read_uleb
437
+ @params[:list] = read_class_array(EncodedCatchHandler, @params[:size])
438
+ end
439
+ end
440
+
441
+ # encoded_catch_handler
442
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
443
+ class EncodedCatchHandler < DexObject
444
+ private
445
+ def parse
446
+ @params[:size] = read_sleb
447
+ @params[:list] = read_class_array(EncodedTypeAddrPair, @params[:size].abs)
448
+ @params[:catch_all_addr] = read_uleb if @params[:size] <= 0
449
+ end
450
+ end
451
+
452
+ # encoded_type_addr_pair
453
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
454
+ class EncodedTypeAddrPair < DexObject
455
+ private
456
+ def parse
457
+ @params[:type_idx] = read_uleb
458
+ @params[:addr] = read_uleb
459
+ end
460
+ end
461
+
462
+ # debug_info_item
463
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
464
+ class DebugInfoItem < DexObject
465
+ private
466
+ def parse
467
+ @params[:line_start] = read_uleb
468
+ @params[:parameters_size] = read_uleb
469
+ @params[:parameter_names] = []
470
+ @params[:parameters_size].times { @params[:parameter_names] << read_uleb128p1 }
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end