rusty_axml/chunks/res_table.rs
1#![allow(dead_code)]
2
3//! Resource table
4//!
5//! The resource table data contains a series of additional chunks:
6//! * A `ResTable` containing the chunk header and the number of packages values.
7//! * One or more `ResTablePackage` chunks.
8//!
9//! Specific entries within a resource table can be uniquely identified
10//! with a single integer as defined by the ResTable_ref structure.
11
12use crate::{
13 chunks::{
14 chunk_header::ChunkHeader,
15 chunk_types::ChunkType,
16 string_pool::StringPool
17 },
18 errors::AxmlError
19};
20
21use std::io::Cursor;
22
23use byteorder::{
24 LittleEndian,
25 ReadBytesExt
26};
27
28/// Header for a resource table
29pub struct ResTable {
30 /// Chunk header
31 header: ChunkHeader,
32
33 /// The number of ResTable_package structures
34 pub package_count: u32,
35}
36
37impl ResTable {
38 /// Parse from a cursor of bytes
39 pub fn parse(axml_buff: &mut Cursor<Vec<u8>>) -> Result<Self, AxmlError> {
40 // Go back 2 bytes, to account from the block type
41 let initial_offset = axml_buff.position();
42 axml_buff.set_position(initial_offset - 2);
43
44 // Parse chunk header
45 let header = ChunkHeader::from_buff(axml_buff, ChunkType::ResTableType)?;
46
47 // Get package count
48 let package_count = axml_buff.read_u32::<LittleEndian>()?;
49
50 let mut strings = Vec::<String>::new();
51
52 // TODO: these are just ignored
53 for _ in 0..package_count {
54 let block_type = ChunkType::parse_block_type(axml_buff)?;
55 match block_type {
56 ChunkType::ResStringPoolType => {
57 StringPool::from_buff(axml_buff, &mut strings)?;
58 },
59 ChunkType::ResTablePackageType => {
60 ResTablePackage::parse(axml_buff)?;
61 },
62 _ => { panic!("######## Unexpected block type: {block_type:02X}"); }
63 };
64 }
65
66 Ok(Self {
67 header,
68 package_count
69 })
70 }
71}
72
73/// A collection of resource data types within a package. Followed by
74/// one or more ResTable_type and ResTable_typeSpec structures containing the
75/// entry values for each resource type.
76///
77/// TODO: we do not deal with the following structs
78#[derive(Debug)]
79pub struct ResTablePackage {
80 // Package header
81 header: ChunkHeader,
82
83 // If this is a base package, its ID. Package IDs
84 // at 1 (corresponding to the value of the package bits in a
85 // resource identifier). 0 means this is not a base package.
86 id: u32,
87
88 // Actual name of this package, \0-terminated.
89 name: [u16; 128],
90
91 // Offset to a ResStringPool_header defining the resource
92 // type symbol table. If zero, this package is inheriting from
93 // another base package (overriding specific values in it).
94 type_strings: u32,
95
96 // Last index into typeStrings that is for public use by others.
97 last_public_type: u32,
98
99 // Offset to a ResStringPool_header defining the resource key
100 // symbol table. If zero, this package is inheriting from another
101 // base package (overriding specific values in it).
102 key_strings: u32,
103
104 // Last index into keyStrings that is for public use by others.
105 last_public_key: u32,
106
107 // Type ID offset
108 type_id_offset: u32,
109}
110
111impl ResTablePackage {
112 /// Parse from a cursor of bytes
113 pub fn parse(axml_buff: &mut Cursor<Vec<u8>>) -> Result<Self, AxmlError> {
114
115 // Go back 2 bytes, to account from the block type
116 let initial_offset = axml_buff.position();
117 axml_buff.set_position(initial_offset - 2);
118
119 // Parse chunk header
120 let header = ChunkHeader::from_buff(axml_buff, ChunkType::ResTablePackageType)?;
121
122 // Get other members
123 let id = axml_buff.read_u32::<LittleEndian>()?;
124
125 let mut name: [u16; 128] = [0; 128];
126 for item in &mut name {
127 *item = axml_buff.read_u16::<LittleEndian>()?;
128 if *item == 0x00 {
129 break;
130 }
131 }
132 let type_strings = axml_buff.read_u32::<LittleEndian>()?;
133 let last_public_type = axml_buff.read_u32::<LittleEndian>()?;
134 let key_strings = axml_buff.read_u32::<LittleEndian>()?;
135 let last_public_key = axml_buff.read_u32::<LittleEndian>()?;
136 let type_id_offset = axml_buff.read_u32::<LittleEndian>()?;
137
138 // Build and return the object
139 Ok(ResTablePackage {
140 header,
141 id,
142 name,
143 type_strings,
144 last_public_type,
145 key_strings,
146 last_public_key,
147 type_id_offset
148 })
149 }
150}