android_parser 2.4.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.
- checksums.yaml +7 -0
- data/.gitignore +54 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +45 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +92 -0
- data/LICENSE.txt +22 -0
- data/README.md +158 -0
- data/Rakefile +44 -0
- data/android_parser.gemspec +64 -0
- data/lib/android/apk.rb +220 -0
- data/lib/android/axml_parser.rb +239 -0
- data/lib/android/axml_writer.rb +49 -0
- data/lib/android/dex/access_flag.rb +74 -0
- data/lib/android/dex/dex_object.rb +475 -0
- data/lib/android/dex/info.rb +151 -0
- data/lib/android/dex/utils.rb +45 -0
- data/lib/android/dex.rb +92 -0
- data/lib/android/layout.rb +44 -0
- data/lib/android/manifest.rb +350 -0
- data/lib/android/resource.rb +621 -0
- data/lib/android/utils.rb +55 -0
- data/lib/ruby_apk.rb +8 -0
- metadata +193 -0
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            require 'rexml/document'
         | 
| 2 | 
            +
            require 'stringio'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Android
         | 
| 5 | 
            +
              class AXMLWriter < AXMLParser
         | 
| 6 | 
            +
                # @param [String] axml binary xml data
         | 
| 7 | 
            +
                def initialize(axml)
         | 
| 8 | 
            +
                  @io = StringIO.new(axml, "r+b")
         | 
| 9 | 
            +
                  @strings = []
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def modify_metadata!(name, new_value)
         | 
| 13 | 
            +
                  parse if @doc.nil?
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  entry = @metadata.find { |meta| meta['android:name'][:value] == name }
         | 
| 16 | 
            +
                  raise "Metadata #{name} could not be found and modified" if entry.nil?
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  pos = if entry['android:value'][:is_string]
         | 
| 19 | 
            +
                          new_string_id = add_string!(new_value)
         | 
| 20 | 
            +
                          new_value = new_string_id
         | 
| 21 | 
            +
                          entry['android:value'][:val_str_id]
         | 
| 22 | 
            +
                        else
         | 
| 23 | 
            +
                          entry['android:value'][:position]
         | 
| 24 | 
            +
                        end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  @io.pos = pos
         | 
| 27 | 
            +
                  @io.write([new_value].pack('V'))
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def add_string!(str)
         | 
| 31 | 
            +
                  new_string_id, bytes_added = Resource::ResStringPool.new(@io.string, 8).add_string(str)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  # Update XML size and positions of metadata attributes.
         | 
| 34 | 
            +
                  @io.pos = 4
         | 
| 35 | 
            +
                  xml_size = @io.read(4).unpack1('V')
         | 
| 36 | 
            +
                  @io.pos = 4
         | 
| 37 | 
            +
                  @io.write([xml_size + bytes_added].pack('V'))
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  @metadata = @metadata.map do |metadata|
         | 
| 40 | 
            +
                    metadata.transform_values do |attribute|
         | 
| 41 | 
            +
                      attribute[:position] += bytes_added
         | 
| 42 | 
            +
                      attribute[:val_str_id] += bytes_added
         | 
| 43 | 
            +
                      attribute
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  new_string_id
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
            end
         | 
| @@ -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
         |