Class: ApkResources
- Inherits:
-
Object
- Object
- ApkResources
- Defined in:
- lib/apktools/apkresources.rb
Overview
Class to parse an APK’s resources.arsc data and retrieve resource data associated with a given R.id value
Defined Under Namespace
Classes: ChunkHeader, Package, PackageHeader, ResType, ResTypeConfig, ResTypeEntry, ResTypeSpec, StringPool
Constant Summary collapse
- DEBUG =
:nodoc:
false
Instance Attribute Summary collapse
-
#package_header ⇒ Object
readonly
PackageHeader containing information about all the type and key strings in the package.
-
#packages ⇒ Object
readonly
Hash of Package chunks, keyed by package id.
-
#stringpool_main ⇒ Object
readonly
StringPool containing all value strings in the package.
Instance Method Summary collapse
-
#get_all_keys ⇒ Object
Return hash of all the key values in the file keyed by package id.
-
#get_all_strings ⇒ Object
Return array of all string values in the file.
-
#get_all_types ⇒ Object
Return hash of all the type values in the file keyed by package id.
-
#get_default_resource_value(res_id) ⇒ Object
Obtain the default value for a given resource id.
-
#get_resource_key(res_id, xml_format = false) ⇒ Object
Obtain the key value for a given resource id.
-
#get_resource_value(res_id) ⇒ Object
Obtain the value(s) for a given resource id.
-
#initialize(apk_file) ⇒ ApkResources
constructor
Create a new ApkResources instance from the specified
apk_file
.
Constructor Details
#initialize(apk_file) ⇒ ApkResources
Create a new ApkResources instance from the specified apk_file
This opens and parses the contents of the APK’s resources.arsc file.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/apktools/apkresources.rb', line 134 def initialize(apk_file) data = nil Zip.warn_invalid_date = false # Get resources.arsc from the APK file Zip::File.foreach(apk_file) do |f| if f.name.match(/resources.arsc/) data = f.get_input_stream.read.force_encoding('BINARY') end end # Parse the Table Chunk ## Header header_type = read_short(data, HEADER_START) header_size = read_short(data, HEADER_START+2) header_chunk_size = read_word(data, HEADER_START+4) header_package_count = read_word(data, HEADER_START+8) puts "Resource Package Count = #{header_package_count}" if DEBUG # Parse the StringPool Chunk ## Header startoffset_pool = HEADER_START + header_size puts "Parse Main StringPool Chunk" if DEBUG @stringpool_main = parse_stringpool(data, startoffset_pool) puts "#{@stringpool_main.values.length} strings found" if DEBUG # Parse the Package Chunk ## Header startoffset_package = startoffset_pool + @stringpool_main.header.chunk_size @packages = Hash.new() i = 0 while i < header_package_count package_element = parse_package(data, startoffset_package) puts "Package #{package_element.package_header.id}" if DEBUG startoffset_package = startoffset_package + package_element.package_header.header.chunk_size @packages[package_element.package_header.id] = package_element i += 1 end end |
Instance Attribute Details
#package_header ⇒ Object (readonly)
PackageHeader containing information about all the type and key strings in the package
124 125 126 |
# File 'lib/apktools/apkresources.rb', line 124 def package_header @package_header end |
#packages ⇒ Object (readonly)
Hash of Package chunks, keyed by package id
128 129 130 |
# File 'lib/apktools/apkresources.rb', line 128 def packages @packages end |
#stringpool_main ⇒ Object (readonly)
StringPool containing all value strings in the package
126 127 128 |
# File 'lib/apktools/apkresources.rb', line 126 def stringpool_main @stringpool_main end |
Instance Method Details
#get_all_keys ⇒ Object
Return hash of all the key values in the file keyed by package id
200 201 202 203 204 205 206 207 |
# File 'lib/apktools/apkresources.rb', line 200 def get_all_keys keys = Hash.new() @packages.each do |key, value| keys[key] = value.stringpool_keystrings.values end return keys end |
#get_all_strings ⇒ Object
Return array of all string values in the file
179 180 181 |
# File 'lib/apktools/apkresources.rb', line 179 def get_all_strings return @stringpool_main.values end |
#get_all_types ⇒ Object
Return hash of all the type values in the file keyed by package id
187 188 189 190 191 192 193 194 |
# File 'lib/apktools/apkresources.rb', line 187 def get_all_types types = Hash.new() @packages.each do |key, value| types[key] = value.stringpool_typestrings.values end return types end |
#get_default_resource_value(res_id) ⇒ Object
Obtain the default value for a given resource id
res_id: ID values of a resources as a FixNum or String representation (i.e. 0x7F060001)
Returns: The default ResTypeEntry to the given id, or nil if no default exists
262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/apktools/apkresources.rb', line 262 def get_default_resource_value(res_id) if res_id.is_a? String res_id = res_id.hex end entries = get_resource_value(res_id) if entries != nil default = ResTypeConfig.new(0, 0, 0, 0, 0, 0, 0, 0) default_entry = entries[default] return default_entry else return nil end end |
#get_resource_key(res_id, xml_format = false) ⇒ Object
Obtain the key value for a given resource id
res_id: ID value of a resource as a FixNum or String representation (i.e. 0x7F060001) xml_format: Optionally format return string for XML files.
If xml_format is true, return value will be @<type>/<key> If xml_format is false or missing, return value will be R.<type>.<key> If the resource id does not exist, return value will be nil
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/apktools/apkresources.rb', line 219 def get_resource_key(res_id, xml_format=false) if res_id.is_a? String res_id = res_id.hex end # R.id integers are a concatenation of package_id, type_id, and entry index res_package = (res_id >> 24) & 0xFF res_type = (res_id >> 16) & 0xFF res_index = res_id & 0xFFFF package_element = @packages[res_package] if package_element == nil # This is not a resource we can parse return nil end res_spec = package_element.type_data[res_type-1] if res_spec == nil puts "Could not find ResTypeSpec for #{res_package} #{res_type}" if DEBUG return nil end entry = res_spec.types.entries[res_index] if entry == nil || entry.values.empty? # There is no entry in our table for this resource puts "Could not find #{res_spec.types.id} ResType chunk" if DEBUG return nil end if xml_format return "@#{res_spec.id}/#{entry.values[0].key}" else return "R.#{res_spec.id}.#{entry.values[0].key}" end end |
#get_resource_value(res_id) ⇒ Object
Obtain the value(s) for a given resource id. A default resource is one defined in an unqualified directory.
res_id: ID value of a resource as a FixNum or String representation (i.e. 0x7F060001)
Returns: Hash of all entries matching this id, keyed by their matching ResTypeConfig or nil if the resource id cannot be found.
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/apktools/apkresources.rb', line 286 def get_resource_value(res_id) if res_id.is_a? String res_id = res_id.hex end # R.id integers are a concatenation of package_id, type_id, and entry index res_package = (res_id >> 24) & 0xFF res_type = (res_id >> 16) & 0xFF res_index = res_id & 0xFFFF package_element = @packages[res_package] if package_element == nil # This is not a resource we can parse return nil end res_spec = package_element.type_data[res_type-1] if res_spec == nil puts "Could not find ResTypeSpec for #{res_package} #{res_type}" if DEBUG return nil end entries = res_spec.types.entries[res_index] if entries == nil puts "Could not find #{res_spec.types.id} ResType chunk" if DEBUG return nil end return entries end |