内容简介:上篇博客写到,Package资源剩下的部分是由多组RES_TABLE_TYPE_SPEC_TYPE和RES_TABLE_TYPE_TYPE构成的。一个RES_TABLE_TYPE_SPEC_TYPE后面跟着一个或者多个RES_TABLE_TYPE_TYPE构成一种类型的资源的描述(例如string类型、bool类型、dimen类型等)我们接着来看看RES_TABLE_TYPE_SPEC_TYPE的头部结构体:
上篇博客写到,Package资源剩下的部分是由多组RES_TABLE_TYPE_SPEC_TYPE和RES_TABLE_TYPE_TYPE构成的。
一个RES_TABLE_TYPE_SPEC_TYPE后面跟着一个或者多个RES_TABLE_TYPE_TYPE构成一种类型的资源的描述(例如string类型、bool类型、dimen类型等)
RES_TABLE_TYPE_SPEC_TYPE
我们接着来看看RES_TABLE_TYPE_SPEC_TYPE的头部结构体:
/** * A specification of the resources defined by a particular type. * * There should be one of these chunks for each resource type. * * This structure is followed by an array of integers providing the set of * configuration change flags (ResTable_config::CONFIG_*) that have multiple * resources for that configuration. In addition, the high bit is set if that * resource has been made public. */ struct ResTable_typeSpec { struct ResChunk_header header; // The type identifier this chunk is holding. Type IDs start // at 1 (corresponding to the value of the type bits in a // resource identifier). 0 is invalid. uint8_t id; // Must be 0. uint8_t res0; // Must be 0. uint16_t res1; // Number of uint32_t entry configuration masks that follow. uint32_t entryCount; enum { // Additional flag indicating an entry is public. SPEC_PUBLIC = 0x40000000 }; };
从注释中可以知道ResTable_typeSpec头部后面会跟着entryCount个uint32_t,代表这种类型有entryCount个数据,并且每个uint32_t标识了这个数据在哪些configuration下有特殊的值。
这些configuration可能是不同的地区、不同的屏幕分辨率、不同的sdk版本等:
// Flags indicating a set of config values. These flag constants must // match the corresponding ones in android.content.pm.ActivityInfo and // attrs_manifest.xml. enum { CONFIG_MCC = ACONFIGURATION_MCC, CONFIG_MNC = ACONFIGURATION_MCC, CONFIG_LOCALE = ACONFIGURATION_LOCALE, CONFIG_TOUCHSCREEN = ACONFIGURATION_TOUCHSCREEN, CONFIG_KEYBOARD = ACONFIGURATION_KEYBOARD, CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN, CONFIG_NAVIGATION = ACONFIGURATION_NAVIGATION, CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION, CONFIG_DENSITY = ACONFIGURATION_DENSITY, CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE, CONFIG_SMALLEST_SCREEN_SIZE = ACONFIGURATION_SMALLEST_SCREEN_SIZE, CONFIG_VERSION = ACONFIGURATION_VERSION, CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT, CONFIG_UI_MODE = ACONFIGURATION_UI_MODE, CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR, };
这里直接举个例子,例如我们可能会在res/values目录下创建一些bool配置:
<bool name="abc_action_bar_embed_tabs">true</bool> <bool name="abc_allow_stacked_button_bar">false</bool> <bool name="abc_config_actionMenuItemAllCaps">true</bool>
然后可能在竖屏的情况下我们不需要显示action bar,所以在res/values-port目录下我们会把abc_action_bar_embed_tabs的值设置成false
<bool name="abc_action_bar_embed_tabs">false</bool>
然后下面代码就能在横屏、竖屏下拿到不同的配置了:
context.getResources().getBoolean(R.bool.abc_action_bar_embed_tabs);
在代码里面,我们可以先读取ResTable_typeSpec,然后根据entryCount得到这种类型有多少个数据(例如这里的bool就有abc_action_bar_embed_tabs、abc_allow_stacked_button_bar、abc_config_actionMenuItemAllCaps三个数据,所以bool类型下的entryCount就是3),然后继续读entryCount个uint32_t,读出来就是每个数据在哪些configuration下有特殊的值。
//printStringFromStringsPool: void printStringFromStringsPool(uint32_t* pOffsets, char* pStringsStart, uint32_t stringIndex, uint32_t isUtf8) { //前面两个字节是长度,要跳过 char* str = pStringsStart + *(pOffsets + stringIndex) + 2; if(isUtf8) { printf("%s\n", str); } else { printUtf16String((char16_t*)str); } } //main: ... ResTable_typeSpec typeSpecHeader; uint32_t config; uint16_t type; while(fread((void*)&type, sizeof(u_int16_t), 1, pFile) != 0) { fseek(pFile, -sizeof(uint16_t), SEEK_CUR); if(RES_TABLE_TYPE_SPEC_TYPE == type) { fread((void*)&typeSpecHeader, sizeof(struct ResTable_typeSpec), 1, pFile); printf("type: id=0x%x,name=", typeSpecHeader.id); printStringFromStringsPool( (uint32_t*)pTypeStrings, (char*)pTypeStrings + typeStringPoolHeader.stringsStart - sizeof(struct ResStringPool_header), typeSpecHeader.id - 1, typeStringPoolHeader.flags & ResStringPool_header::UTF8_FLAG ); for(int i = 0 ; i < typeSpecHeader.entryCount ; i++) { fread((void*)&config, sizeof(uint32_t), 1, pFile); printf("%x\n",config); } } ... } ...
我们直接找到bool类型下的打印:
... type:id=3,name=bool 80 0 0 ...
可以看到bool类型下的确有三个uint32_t,分别是80、0、0。这个80代表的就是CONFIG_ORIENTATION,也就是说这个数据在不同的屏幕方向下面会有和默认值不同的值。而0则代表了这个数据只有一个默认值,不会跟着configuration的变化而改变:
//configuration.h ACONFIGURATION_ORIENTATION = 0x0080, //ResTable_config里面的enum CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION,
让我们返回去对比下:
// res/values目录下 <bool name="abc_action_bar_embed_tabs">true</bool> <bool name="abc_allow_stacked_button_bar">false</bool> <bool name="abc_config_actionMenuItemAllCaps">true</bool> // res/values-port目录下 <bool name="abc_action_bar_embed_tabs">false</bool>
第一个abc_action_bar_embed_tabs在不同的屏幕方向下可能值会改变,所以它的uint32_t值是80,也就是CONFIG_ORIENTATION,而abc_allow_stacked_button_bar 和abc_config_actionMenuItemAllCaps只有默认的配置,所以他们的uint32_t都是0。
所以RES_TABLE_TYPE_SPEC_TYPE的作用就是将数据受到哪些configuration影响都标识出来。
在读取数据的时候先看看它是否会受configuration影响,如果不会,直接读默认的RES_TABLE_TYPE_TYPE里面的默认值就好,否则就根据当前的configuration去到后面对应的RES_TABLE_TYPE_TYPE下面读取对应的值了。
RES_TABLE_TYPE_TYPE
讲的这里终于到了最重要的部分,我们在xml里面配的值,都会在RES_TABLE_TYPE_TYPE里面体现出来。
我们照例先来看看它的头部结构体:
/** * A collection of resource entries for a particular resource data * type. Followed by an array of uint32_t defining the resource * values, corresponding to the array of type strings in the * ResTable_package::typeStrings string block. Each of these hold an * index from entriesStart; a value of NO_ENTRY means that entry is * not defined. * * There may be multiple of these chunks for a particular resource type, * supply different configuration variations for the resource values of * that type. * * It would be nice to have an additional ordered index of entries, so * we can do a binary search if trying to find a resource by string name. */ struct ResTable_type { struct ResChunk_header header; enum { NO_ENTRY = 0xFFFFFFFF }; // The type identifier this chunk is holding. Type IDs start // at 1 (corresponding to the value of the type bits in a // resource identifier). 0 is invalid. uint8_t id; // Must be 0. uint8_t res0; // Must be 0. uint16_t res1; // Number of uint32_t entry indices that follow. uint32_t entryCount; // Offset from header where ResTable_entry data starts. uint32_t entriesStart; ResTable_config config; };
这个ResTable_type里有个config成员,它就是具体的配置了,我们可以把它打印出来:
else if(RES_TABLE_TYPE_TYPE == type) { fread((void*)&typeHeader, sizeof(struct ResTable_type), 1, pFile); printConfig(typeHeader.config); ... }
找到bool的那一段,可以看到它有两个RES_TABLE_TYPE_TYPE,第一个是默认的配置(values目录),第二个是port下的配置(values-port目录):
... type: id=0x3,name=bool 80 0 0 config : config : port ...
然后根据注释的说明我们知道,ResTable_type头部后跟着entryCount个uint32_t,代表了每个entry相对entriesStart的偏移。这里和RES_STRING_POOL_TYPE有点像,也是从偏移数组读取数据的偏移值,然后从entriesStart进行偏移得到数据的地址。
那entriesStart后面的entry是什么呢?其实entry有两种类型ResTable_entry和ResTable_map_entry。
他们其实是有继承关系的,ResTable_map_entry是ResTable_entry的子类(这里的继承关系是c++里面的继承关系,前面我们都是用 c语言 去讲的,但是这里必须引入c++了,不过也是最基础的继承而已,大家可以自行搜索下)。
/** * This is the beginning of information about an entry in the resource * table. It holds the reference to the name of this entry, and is * immediately followed by one of: * * A Res_value structure, if FLAG_COMPLEX is -not- set. * * An array of ResTable_map structures, if FLAG_COMPLEX is set. * These supply a set of name/value mappings of data. */ struct ResTable_entry { // Number of bytes in this structure. uint16_t size; enum { // If set, this is a complex entry, holding a set of name/value // mappings. It is followed by an array of ResTable_map structures. FLAG_COMPLEX = 0x0001, // If set, this resource has been declared public, so libraries // are allowed to reference it. FLAG_PUBLIC = 0x0002, // If set, this is a weak resource and may be overriden by strong // resources of the same name/type. This is only useful during // linking with other resource tables. FLAG_WEAK = 0x0004 }; uint16_t flags; // Reference into ResTable_package::keyStrings identifying this entry. struct ResStringPool_ref key; }; /** * Extended form of a ResTable_entry for map entries, defining a parent map * resource from which to inherit values. */ struct ResTable_map_entry : public ResTable_entry { // Resource identifier of the parent mapping, or 0 if there is none. ResTable_ref parent; // Number of name/value pairs that follow for FLAG_COMPLEX. uint32_t count; };
看到注释我们可以知道, ResTable_entry有个flags成员变量,如果它的FLAG_COMPLEX位被置1(也就是说flags & 0x0001 != 0),则它是个ResTable_map_entry结构。
两种结构的不同之处在于ResTable_entry后面跟着的是一个Res_value,而ResTable_map_entry后面跟着的是多个name/value键值对,这个键值对是用struct ResTable_map来表示的。
ResTable_entry
我们先从ResTable_entry讲起,我们读完struct ResTable_type头部信息之后继续将offset数组和entriesStart开始到剩下的部分都读进去保存到pOffset和pData中。
接着就可以用*(pOffsets + i)得到每个entry的偏移,再与entriesStart相加得到entry的具体位置。这里有一点需要注意的是如果offset是ResTable_type::NO_ENTRY,也就是0xFFFFFFFF的时候,代表它是无效的,直接跳过即可:
else if(RES_TABLE_TYPE_TYPE == type) { fread((void*)&typeHeader, sizeof(struct ResTable_type), 1, pFile); printConfig(typeHeader.config); // 实际struct ResTable_type的大小可能不同sdk版本不一样,所以typeHeader.header.headerSize才是真正的头部大小 fseek(pFile, typeHeader.header.headerSize - sizeof(struct ResTable_type), SEEK_CUR);; uint32_t* pOffsets = (uint32_t*)malloc(typeHeader.entryCount * sizeof(uint32_t)); fread((void*)pOffsets, sizeof(uint32_t), typeHeader.entryCount, pFile); unsigned char* pData = (unsigned char*)malloc(typeHeader.header.size - typeHeader.entriesStart); fread((void*)pData, typeHeader.header.size - typeHeader.entriesStart, 1, pFile); for(int i = 0 ; i< typeHeader.entryCount ; i++) { uint32_t offset = *(pOffsets + i); if(offset == ResTable_type::NO_ENTRY) { continue; } struct ResTable_entry* pEntry = (struct ResTable_entry*)(pData + offset); printf("entryIndex: 0x%x, key :\n", i); printStringFromStringsPool( (uint32_t*)pKeyStrings, (char*)pKeyStrings + keyStringPoolHeader.stringsStart - sizeof(struct ResStringPool_header), pEntry->key.index, keyStringPoolHeader.flags & ResStringPool_header::UTF8_FLAG ); if(pEntry->flags & ResTable_entry::FLAG_COMPLEX) { ... } else { struct Res_value* pValue = (struct Res_value*)((unsigned char*)pEntry + sizeof(struct ResTable_entry)); printf("value :\n"); printValue(pValue, globalStringPoolHeader, pGlobalStrings); printf("\n"); } } free(pOffsets); free(pData); }
pEntry->key.index就是资源的key在资源key字符串池中的序号了,直接打印即可。
然后找到struct ResTable_entry后面跟着的struct Res_value,这个结构体里面就是资源的值。但是这个值的获取比较复杂,我们先来看看这个结构体的定义:
/** * Representation of a value in a resource, supplying type * information. */ struct Res_value { // Number of bytes in this structure. uint16_t size; // Always set to 0. uint8_t res0; // Type of the data value. enum { // The 'data' is either 0 or 1, specifying this resource is either // undefined or empty, respectively. TYPE_NULL = 0x00, // The 'data' holds a ResTable_ref, a reference to another resource // table entry. TYPE_REFERENCE = 0x01, // The 'data' holds an attribute resource identifier. TYPE_ATTRIBUTE = 0x02, // The 'data' holds an index into the containing resource table's // global value string pool. TYPE_STRING = 0x03, // The 'data' holds a single-precision floating point number. TYPE_FLOAT = 0x04, // The 'data' holds a complex number encoding a dimension value, // such as "100in". TYPE_DIMENSION = 0x05, // The 'data' holds a complex number encoding a fraction of a // container. TYPE_FRACTION = 0x06, // The 'data' holds a dynamic ResTable_ref, which needs to be // resolved before it can be used like a TYPE_REFERENCE. TYPE_DYNAMIC_REFERENCE = 0x07, // The 'data' holds an attribute resource identifier, which needs to be resolved // before it can be used like a TYPE_ATTRIBUTE. TYPE_DYNAMIC_ATTRIBUTE = 0x08, // Beginning of integer flavors... TYPE_FIRST_INT = 0x10, // The 'data' is a raw integer value of the form n..n. TYPE_INT_DEC = 0x10, // The 'data' is a raw integer value of the form 0xn..n. TYPE_INT_HEX = 0x11, // The 'data' is either 0 or 1, for input "false" or "true" respectively. TYPE_INT_BOOLEAN = 0x12, // Beginning of color integer flavors... TYPE_FIRST_COLOR_INT = 0x1c, // The 'data' is a raw integer value of the form #aarrggbb. TYPE_INT_COLOR_ARGB8 = 0x1c, // The 'data' is a raw integer value of the form #rrggbb. TYPE_INT_COLOR_RGB8 = 0x1d, // The 'data' is a raw integer value of the form #argb. TYPE_INT_COLOR_ARGB4 = 0x1e, // The 'data' is a raw integer value of the form #rgb. TYPE_INT_COLOR_RGB4 = 0x1f, // ...end of integer flavors. TYPE_LAST_COLOR_INT = 0x1f, // ...end of integer flavors. TYPE_LAST_INT = 0x1f }; uint8_t dataType; // Structure of complex data values (TYPE_UNIT and TYPE_FRACTION) enum { // Where the unit type information is. This gives us 16 possible // types, as defined below. COMPLEX_UNIT_SHIFT = 0, COMPLEX_UNIT_MASK = 0xf, // TYPE_DIMENSION: Value is raw pixels. COMPLEX_UNIT_PX = 0, // TYPE_DIMENSION: Value is Device Independent Pixels. COMPLEX_UNIT_DIP = 1, // TYPE_DIMENSION: Value is a Scaled device independent Pixels. COMPLEX_UNIT_SP = 2, // TYPE_DIMENSION: Value is in points. COMPLEX_UNIT_PT = 3, // TYPE_DIMENSION: Value is in inches. COMPLEX_UNIT_IN = 4, // TYPE_DIMENSION: Value is in millimeters. COMPLEX_UNIT_MM = 5, // TYPE_FRACTION: A basic fraction of the overall size. COMPLEX_UNIT_FRACTION = 0, // TYPE_FRACTION: A fraction of the parent size. COMPLEX_UNIT_FRACTION_PARENT = 1, // Where the radix information is, telling where the decimal place // appears in the mantissa. This give us 4 possible fixed point // representations as defined below. COMPLEX_RADIX_SHIFT = 4, COMPLEX_RADIX_MASK = 0x3, // The mantissa is an integral number -- i.e., 0xnnnnnn.0 COMPLEX_RADIX_23p0 = 0, // The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn COMPLEX_RADIX_16p7 = 1, // The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn COMPLEX_RADIX_8p15 = 2, // The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn COMPLEX_RADIX_0p23 = 3, // Where the actual value is. This gives us 23 bits of // precision. The top bit is the sign. COMPLEX_MANTISSA_SHIFT = 8, COMPLEX_MANTISSA_MASK = 0xffffff }; // Possible data values for TYPE_NULL. enum { // The value is not defined. DATA_NULL_UNDEFINED = 0, // The value is explicitly defined as empty. DATA_NULL_EMPTY = 1 }; // The data for this item, as interpreted according to dataType. typedef uint32_t data_type; data_type data; };
我们先需要根据dataType判断这个值是什么类型的,然后再根据不同的类型,从data读取具体的值。读取的方法比较复杂,我就不具体讲解,大家可以参考我的demo代码理解。
我们找到bool部分的打印,可以看到key和value就都打印出来了:
type: id=0x3,name=bool 80 0 0 config : entryIndex: 0x0, key : abc_action_bar_embed_tabs value : (boolean) true entryIndex: 0x1, key : abc_allow_stacked_button_bar value : (boolean) false entryIndex: 0x2, key : abc_config_actionMenuItemAllCaps value : (boolean) true config : port entryIndex: 0x0, key : abc_action_bar_embed_tabs value : (boolean) false
ResTable_map_entry
从上面可以看出来ResTable_entry代表的是普通键值对的资源如string、bool、drawable等,那ResTable_map_entry又代表的是啥呢?
其实它代表的是类型style、attr的资源:
<attr name="buttonTintMode"> <enum name="src_over" value="3"/> <enum name="src_in" value="5"/> <enum name="src_atop" value="9"/> <enum name="multiply" value="14"/> <enum name="screen" value="15"/> <enum name="add" value="16"/> </attr> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
像上面的R.attr.buttonTintMode和R.style.AppTheme的值都需要用一个map去表示。
我们来看看struct ResTable_map_entry:
/** * Extended form of a ResTable_entry for map entries, defining a parent map * resource from which to inherit values. */ struct ResTable_map_entry : public ResTable_entry { // Resource identifier of the parent mapping, or 0 if there is none. ResTable_ref parent; // Number of name/value pairs that follow for FLAG_COMPLEX. uint32_t count; };
它的parent成员变量就定义了这个style的parent,count成员变量则代表了这个map的大小,也就是ResTable_map_entry后面跟着的键值对的数量。
资源的id
struct ResTable_ref也是一个需要重点讲解的结构体,它的定义很简单:
/** * This is a reference to a unique entry (a ResTable_entry structure) * in a resource table. The value is structured as: 0xpptteeee, * where pp is the package index, tt is the type index in that * package, and eeee is the entry index in that type. The package * and type values start at 1 for the first item, to help catch cases * where they have not been supplied. */ struct ResTable_ref { uint32_t ident; };
这个ident代表的就是资源的id。这个值其实我们在 java 里面也能看到:
public final class R { ... public static final class bool { public static final int abc_action_bar_embed_tabs=0x7f030000; public static final int abc_allow_stacked_button_bar=0x7f030001; public static final int abc_config_actionMenuItemAllCaps=0x7f030002; } ... }
资源的id其实是有固定的格式和含义的,它的格式如下:
0xpptteeee
头一个字节保存了packageId,接着的一个字节保存了typeId,后面的两个字节保存了entryIndex。例如我们的abc_allow_stacked_button_bar=0x7f030001,它的packageId=0x7f, typeId=0x3, entryIndex=0x1。
我们在解析package资源的时候就已经把package id打印了出来,它就是0x7f:
type:512, headSize:288, size:188068, id:7f, packageName:com.cvte.tv.myapplication
而在后面解析资源的时候也把typeId和entryIndex打印了出来:
type: id=0x3,name=bool 80 0 0 config : entryIndex: 0x0, key : abc_action_bar_embed_tabs value : (boolean) true entryIndex: 0x1, key : abc_allow_stacked_button_bar
于是乎我们就能定位到abc_allow_stacked_button_bar这个资源了。
所以我们的style的parent.ident就可以定位到style的parent资源。
有时候我们会看到packageId是0x01,在我们的resource.arsc里面找不到对应的package。这个package指定其实是系统资源包,我们在xml里面配置的@android:color/black就会使用到系统资源包里面的资源,这个资源是不会打包进我们的应用的:
... type: id=0x4,name=color ... entryIndex: 0x41, key : primary_dark_material_dark value : (reference) 0x0106000c ...
ResTable_map
ResTable_map_entry后面跟着的键值对数组其实就是一个个的ResTable_map:
struct ResTable_map定义如下:
/** * A single name/value mapping that is part of a complex resource * entry. */ struct ResTable_map { // The resource identifier defining this mapping's name. For attribute // resources, 'name' can be one of the following special resource types // to supply meta-data about the attribute; for all other resource types // it must be an attribute resource. ResTable_ref name; // Special values for 'name' when defining attribute resources. enum { // This entry holds the attribute's type code. ATTR_TYPE = Res_MAKEINTERNAL(0), // For integral attributes, this is the minimum value it can hold. ATTR_MIN = Res_MAKEINTERNAL(1), // For integral attributes, this is the maximum value it can hold. ATTR_MAX = Res_MAKEINTERNAL(2), // Localization of this resource is can be encouraged or required with // an aapt flag if this is set ATTR_L10N = Res_MAKEINTERNAL(3), // for plural support, see android.content.res.PluralRules#attrForQuantity(int) ATTR_OTHER = Res_MAKEINTERNAL(4), ATTR_ZERO = Res_MAKEINTERNAL(5), ATTR_ONE = Res_MAKEINTERNAL(6), ATTR_TWO = Res_MAKEINTERNAL(7), ATTR_FEW = Res_MAKEINTERNAL(8), ATTR_MANY = Res_MAKEINTERNAL(9) }; // Bit mask of allowed types, for use with ATTR_TYPE. enum { // No type has been defined for this attribute, use generic // type handling. The low 16 bits are for types that can be // handled generically; the upper 16 require additional information // in the bag so can not be handled generically for TYPE_ANY. TYPE_ANY = 0x0000FFFF, // Attribute holds a references to another resource. TYPE_REFERENCE = 1<<0, // Attribute holds a generic string. TYPE_STRING = 1<<1, // Attribute holds an integer value. ATTR_MIN and ATTR_MIN can // optionally specify a constrained range of possible integer values. TYPE_INTEGER = 1<<2, // Attribute holds a boolean integer. TYPE_BOOLEAN = 1<<3, // Attribute holds a color value. TYPE_COLOR = 1<<4, // Attribute holds a floating point value. TYPE_FLOAT = 1<<5, // Attribute holds a dimension value, such as "20px". TYPE_DIMENSION = 1<<6, // Attribute holds a fraction value, such as "20%". TYPE_FRACTION = 1<<7, // Attribute holds an enumeration. The enumeration values are // supplied as additional entries in the map. TYPE_ENUM = 1<<16, // Attribute holds a bitmaks of flags. The flag bit values are // supplied as additional entries in the map. TYPE_FLAGS = 1<<17 }; // Enum of localization modes, for use with ATTR_L10N. enum { L10N_NOT_REQUIRED = 0, L10N_SUGGESTED = 1 }; // This mapping's value. Res_value value; };
它的name代表的就是这个键值对的key,而它的value代表的就是键值对的值。
name同样的是个struct ResTable_ref,它同样可以从资源id拿到对应的资源,但是这个name有点特殊,如果是它的ident的值是下面枚举中的一个的话:
#define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF)) enum { // This entry holds the attribute's type code. ATTR_TYPE = Res_MAKEINTERNAL(0), // For integral attributes, this is the minimum value it can hold. ATTR_MIN = Res_MAKEINTERNAL(1), // For integral attributes, this is the maximum value it can hold. ATTR_MAX = Res_MAKEINTERNAL(2), // Localization of this resource is can be encouraged or required with // an aapt flag if this is set ATTR_L10N = Res_MAKEINTERNAL(3), // for plural support, see android.content.res.PluralRules#attrForQuantity(int) ATTR_OTHER = Res_MAKEINTERNAL(4), ATTR_ZERO = Res_MAKEINTERNAL(5), ATTR_ONE = Res_MAKEINTERNAL(6), ATTR_TWO = Res_MAKEINTERNAL(7), ATTR_FEW = Res_MAKEINTERNAL(8), ATTR_MANY = Res_MAKEINTERNAL(9) };
例如如果index==0x01000000,就代表name是ATTR_TYPE,也代表这个资源是attr。
此时,它的value也是特殊的,是下面枚举中的一个,代表attr的类型:
enum { // No type has been defined for this attribute, use generic // type handling. The low 16 bits are for types that can be // handled generically; the upper 16 require additional information // in the bag so can not be handled generically for TYPE_ANY. TYPE_ANY = 0x0000FFFF, // Attribute holds a references to another resource. TYPE_REFERENCE = 1<<0, // Attribute holds a generic string. TYPE_STRING = 1<<1, // Attribute holds an integer value. ATTR_MIN and ATTR_MIN can // optionally specify a constrained range of possible integer values. TYPE_INTEGER = 1<<2, // Attribute holds a boolean integer. TYPE_BOOLEAN = 1<<3, // Attribute holds a color value. TYPE_COLOR = 1<<4, // Attribute holds a floating point value. TYPE_FLOAT = 1<<5, // Attribute holds a dimension value, such as "20px". TYPE_DIMENSION = 1<<6, // Attribute holds a fraction value, such as "20%". TYPE_FRACTION = 1<<7, // Attribute holds an enumeration. The enumeration values are // supplied as additional entries in the map. TYPE_ENUM = 1<<16, // Attribute holds a bitmaks of flags. The flag bit values are // supplied as additional entries in the map. TYPE_FLAGS = 1<<17 };
解析代码如下:
if(pEntry->flags & ResTable_entry::FLAG_COMPLEX) { struct ResTable_map_entry* pMapEntry = (struct ResTable_map_entry*)(pData + offset); for(int i = 0; i <pMapEntry->count ; i++) { struct ResTable_map* pMap = (struct ResTable_map*)(pData + offset + pMapEntry->size + i * sizeof(struct ResTable_map_entry)); printf("\tname:0x%x, valueType:%u, value:%u\n", pMap->name.ident, pMap->value.dataType, pMap->value.data); } }
让我们找到buttonTintMode的打印
entryIndex: 0x69, key : buttonTintMode name:0x1000000, valueType:16, value:65536 name:0x7f070019, valueType:16, value:16 name:0x7f070050, valueType:16, value:14 name:0x7f070061, valueType:16, value:15 name:0x7f070078, valueType:16, value:9 name:0x7f070079, valueType:16, value:5 name:0x7f07007a, valueType:16, value:3
第一个ResTable_ref的name的indent的值是0x1000000,就代表name是ATTR_TYPE,也代表这个资源是attr。然后value是65536,也就是TYPE_ENUM。
然后我们顺便找下7f070019、7f070050、7f070061、7f070078、7f070079、7f07007a资源的定义:
... type: id=0x7,name=id ... entryIndex: 0x19, key : add value : (boolean) false ... entryIndex: 0x50, key : multiply value : (boolean) false ... entryIndex: 0x61, key : screen value : (boolean) false ... entryIndex: 0x78, key : src_atop value : (boolean) false entryIndex: 0x79, key : src_in value : (boolean) false entryIndex: 0x7a, key : src_over value : (boolean) false
Demo
完整的demo可以在github上找到:
https://github.com/bluesky466/ResourcesArscDemo
呼~长舒一口气,终于大功告成。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 全网最全 Dalvik 指令集解析 !
- 可能是全网讲最细的安卓resources.arsc解析教程(一)
- 全网最全 | MySQL EXPLAIN 完全解读
- 全网最全Flutter常用工具类
- 全网最通透的 Java 8 版本特性讲解
- 全网首发!Laravel 远程代码执行漏洞 POC
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
DOM Scripting
Jeremy Keith / friendsofED / 2010-12 / GBP 27.50
There are three main technologies married together to create usable, standards-compliant web designs: XHTML for data structure, Cascading Style Sheets for styling your data, and JavaScript for adding ......一起来看看 《DOM Scripting》 这本书的介绍吧!