resource.arsc二进制内容解析 之 RES_TABLE_TYPE_TYPE (Config List)

目录

1、resource.arsc结构

2、RES_TABLE_TYPE_TYPE

3、ResTable_type

4、ResTable_entry偏移数组

5、ResTable_entry(非bag)

6、Res_value

7、bag类型的RES_TABLE_TYPE_TYPE

8、总结


1、resource.arsc结构

我们先来看resource.arsc的结构如图:

(本来网上有一张神图,但是结构表现的不够清晰,而且比较旧了,缺少了一些新的东西,所以我根据神图自己又重新整理了一张架构图,其中新的东西是指Dynamic package reference,具体可以阅读《resource.arsc二进制内容解析 之 Dynamic package reference》)

在package结构下可以看到有Type Spec(类型规范数据块)和Config List,这块内容是资源索引表中最重要的部分。这一部分也是同一个资源ID在不同配置下,找到不同资源文件的关键。

该部分的整体结构以资源类型Type分段,每段的数据结构相似,都是以ResTable_typeSpec开头,后面紧跟着一个spec数组,和Config List。

Config List就是我们今天研究的关键,这里面包含一些列的RES_TABLE_TYPE_TYPE结构的数据。
 

2、RES_TABLE_TYPE_TYPE

Config List包含若干段数据结构

每段结构都是一个ResTable_type之后紧跟着ResTable_entry偏移数组和若干ResTable_entry。

示例如下:

00000000 00000000  01024C00 500B0000 08000000 8D000000 80020000 38000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000  10000000 20000000
30000000 40000000 50000000 60000000 70000000 80000000 90000000 A0000000
B0000000 C0000000 D0000000 E0000000 F0000000 00010000 10010000 20010000
...
50080000 60080000 70080000 80080000 90080000 A0080000 B0080000 C0080000
08000000 5F020000 08000005 01300000 08000000 60020000 08000005 01380000
08000000 61020000 08000005 01280000 08000000 62020000 08000005 01100000
...
08000000 86020000 08000005 01240000 08000000 87020000 08000001 2E00087F
注意ResTable_entry有两种类型:bag和非bag。示例中仅仅是非bag类型,bag类型后面会细说。
下面我们根据示例来一点点讲解ResTable_type的结构。

3、ResTable_type

首先是ResTable_type,结构如下:
struct ResTable_type  
 {  
     struct ResChunk_header header;  
   
     enum {  
         NO_ENTRY = 0xFFFFFFFF  
     };  
     //标识资源的Type ID  
     uint8_t id;  
     //保留,始终为0  
     uint8_t res0;  
     //保留,始终为0  
     uint16_t res1;  
     //等于本类型的资源项个数,指名称相同的资源项的个数。  
     uint32_t entryCount;  
     //等于资源项数据块相对头部的偏移值。  
     uint32_t entriesStart;  
     //指向一个ResTable_config,用来描述配置信息,地区,语言,分辨率等  
     ResTable_config config;  
 };  
其中ResChunk_header的结构如下:
struct ResChunk_header  
 {  
     enum   
     {  
         RES_NULL_TYPE               = 0x0000,  
         RES_STRING_POOL_TYPE        = 0x0001,  
         RES_TABLE_TYPE              = 0x0002,  
         RES_XML_TYPE                = 0x0003,  
         RES_XML_FIRST_CHUNK_TYPE    = 0x0100,  
         RES_XML_START_NAMESPACE_TYPE= 0x0100,  
         RES_XML_END_NAMESPACE_TYPE  = 0x0101,  
         RES_XML_START_ELEMENT_TYPE  = 0x0102,  
         RES_XML_END_ELEMENT_TYPE    = 0x0103,  
         RES_XML_CDATA_TYPE          = 0x0104,  
         RES_XML_LAST_CHUNK_TYPE     = 0x017f,  
         RES_XML_RESOURCE_MAP_TYPE   = 0x0180,  
         RES_TABLE_PACKAGE_TYPE      = 0x0200,  
         RES_TABLE_TYPE_TYPE         = 0x0201,  
         RES_TABLE_TYPE_SPEC_TYPE    = 0x0202  
     };  
     //当前这个chunk的类型  
     uint16_t type;  
     //当前这个chunk的头部大小  
     uint16_t headerSize;  
     //当前这个chunk的大小  
     uint32_t size;  
 };

ResTable_type就是上面橙色的部分,如下:
01024C00 500B0000 08000000 8D000000 80020000 38000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000 00000000 

一点点解读一下
  • 01024C00 500B0000 是header,其中type是0x201(字序),即RES_TABLE_TYPE_TYPE;头部大小是0x4c,也就是76个;整个chunk大小是0xb50
  • 08000000 是id+res0+res1,所以资源的TypeId是0x08(在示例中是dimen类型的资源,所以是非bag,后面会讲)
  • 8D000000 是entryCount,即资源个数为141(注意字序)
  • 80020000 是entriesStart,即资源数据块相对于头部的偏移量,即偏移0x280(字序)。例子中ResTable_type的大小为76byte;资源个数为141个,所以后面偏移数组有141个,每个偏移量占4byte,则是564byte。这样到资源数据部分正好有640byte,即0x280。偏移数组后面会讲
  • 剩下的就是config了,其中38000000是config的数量,即56个,加上38000000也正好有56byte

4、ResTable_entry偏移数组

在ResTable_type紧跟着是ResTable_entry偏移数组,即绿色部分,每4byte为一个偏移量(相对于资源数据块起始位置的偏移,本例子即头部偏移0x280后的位置),一共有entryCount个即141个偏移量。
这块没必要要详细解释。但是我们注意到例子中这部分偏移量是16byte递增的,说明后面的资源数据块每块是16byte,这个后面我们可以验证。

5、ResTable_entry(非bag)

“ResTable_entry偏移数组”后面就是一系列资源数据块(ResTable_entry),即蓝色部分
数据块分两种,bag和非bag。bag就是有一系列属性的,比如attr、style等。非bag就是单个的,比如color、dimen等
数据块是由ResTable_entry和一个或多个Res_value组成。
非bag的数据块是由ResTable_entry和一个Res_value组成;bag数据块则由ResTable_map_entry(继承自ResTable_entry)和一个或多个Res_value组成。
这里先看非bag数据块,示例中就是非bag数据块。数据结构如下:
struct ResTable_entry  
 {  
     //表示资源项头部大小。  
     uint16_t size;  
   
     enum {  
         //如果flags此位为1,则ResTable_entry后跟随ResTable_map数组,为0则跟随一个Res_value。  
         FLAG_COMPLEX = 0x0001,  
         //如果此位为1,这个一个被引用的资源项  
         FLAG_PUBLIC = 0x0002  
     };  
     //资源项标志位  
     uint16_t flags;  
     //资源项名称在资源项名称字符串资源池的索引  
     struct ResStringPool_ref key;  
 }; 
通过上面我们知道示例中每个数据块都是16byte,我们拿其中一个来举例:
08000000 87020000 08000001 2E00087F
前8byte就是ResTable_entry,后8byte是Res_value(后面再讲),一点点细说
  • 0800 是ResTable_entry大小,即8byte
  • 0000 是flag,0x01(字序)表示是bag,0x00则是非bag
  • 87020000 是该资源项对应的字符串资源的索引

6、Res_value

ResTable_entry后面跟着就是Res_value,它的结构如下:
struct Res_value  
 {  
     //Res_value头部大小  
     uint16_t size;  
     //保留,始终为0  
     uint8_t res0;  
   
     enum {  
         TYPE_NULL = 0x00,  
         TYPE_REFERENCE = 0x01,  
         TYPE_ATTRIBUTE = 0x02,  
         TYPE_STRING = 0x03,  
         TYPE_FLOAT = 0x04,  
         TYPE_DIMENSION = 0x05,  
         TYPE_FRACTION = 0x06,  
         TYPE_FIRST_INT = 0x10,  
         TYPE_INT_DEC = 0x10,  
         TYPE_INT_HEX = 0x11,  
         TYPE_INT_BOOLEAN = 0x12,  
         TYPE_FIRST_COLOR_INT = 0x1c,  
         TYPE_INT_COLOR_ARGB8 = 0x1c,  
         TYPE_INT_COLOR_ARGB8 = 0x1c,  
         TYPE_INT_COLOR_RGB8 = 0x1d,  
         TYPE_INT_COLOR_ARGB4 = 0x1e,  
         TYPE_INT_COLOR_RGB4 = 0x1f,  
         TYPE_LAST_COLOR_INT = 0x1f,  
         TYPE_LAST_INT = 0x1f  
     };  
     //数据的类型,可以从上面的枚举类型中获取  
     uint8_t dataType;  
   
     //数据对应的索引  
     uint32_t data;  
 };  
还用上面的例子来说,如下:
08000000 87020000 08000001 2E00087F
前8byte就是ResTable_entry(前面说过来),后8byte就是Res_value,一点点细说
  • 0800 是Res_value头部大小,非bag就是Res_value的大小,即8byte
  • 00 是res0,固定值
  • 01  是dataType,01表示是引用,即后面的data是一个resId
  • 2E00087F 是数据索引,例子中是一个resId,即0x7F08002E,上面知道type08是dimen,所以这是一个dimen资源

7、bag类型的RES_TABLE_TYPE_TYPE

上面的例子是非bag,下面我们说说bag的例子,示例如下:
00000000 00000000  01024C00 90420000 09000000 7B010000 38060000 38000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000  00000000 34000000 5C000000
6C000000 7C000000 98000000 A8000000 B8000000 C8000000 D8000000 E8000000
...
4C3A0000 8C3A0000 B43A0000 D03A0000 343B0000 743B0000 903B0000 F43B0000 
10000100 EA020000 C700097F 03000000 F300017F 08000005 01180000 F400017F
08000005 01030000 F700017F 08000005 01120000 10000100 EB020000 D200097D
02000000 3601017F 08000010 ...
与非bag相同的部分我们就简单说一下,重点讲不同的部分。
首先、ResTable_type即橙色部分:
  • 01024C00 90420000 是header,type同样是0x201
  • 0900000 是id+res0+res1,所以资源的TypeId是0x09(在示例中是style类型的资源,所以是bag)
  • 7B010000 有0x17b个ResTable_entry
  • 38060000 资源数据块相对与头部偏移0x638。头部大小为76;偏移数组0x17b个,每个4byte。加起来正好0x638
  • 后面是config,其中38000000是config的数量,即56个,加上38000000也正好有56byte
其次、是ResTable_entry偏移数组,即绿色部分,一共0x17b个,每个占用4byte,不细说了。
下面进入资源数据块ResTable_entry,因为是bag,所以数据块是ResTable_map_entry(继承自ResTable_entry),结构如下:
struct ResTable_map_entry : public ResTable_entry  
 {  
     //指向父ResTable_map_entry的资源ID,如果没有父ResTable_map_entry,则等于0。  
     ResTable_ref parent;  
     //等于后面ResTable_map的数量  
     uint32_t count;  
 };  
我们拿第一条举例:
10000100 EA020000 C700097F 03000000 F300017F 08000005 01180000 F400017F
08000005 01030000 F700017F 08000005 01120000
前16byte就是ResTable_map_entry,后面则是Res_value(后面再讲),一点点细说
因为继承,所以首先还是ResTable_entry的结构
  • 1000 是ResTable_entry大小,即0x10(16)byte
  • 0100 是flag,0x01(字序)表示是bag,0x00则是非bag
  • EA020000 是该资源项对应的字符串资源的索引
  • C700097F 就是parent,因为例子是style,所以是这style的parent的resId,即0x7F0900C7
  • 03000000  是ResTable_map的数量,即0x03(字序)
下面就是ResTable_map,结构如下:
struct ResTable_map  
 {  
     //bag资源项ID  
     ResTable_ref name;  
     //bag资源项值  
     Res_value value;  
 };  
例子中有三个,我们拿第一个举例:
F300017F 08000005 01180000

 

8、总结

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BennuCTech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值