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}