• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! package table module defines the package table file format and methods for serialization
18 //! and deserialization
19 
20 use crate::{get_bucket_index, read_str_from_bytes, read_u32_from_bytes, read_u8_from_bytes};
21 use crate::{AconfigStorageError, StorageFileType};
22 use anyhow::anyhow;
23 use std::fmt;
24 
25 /// Package table header struct
26 #[derive(PartialEq)]
27 pub struct PackageTableHeader {
28     pub version: u32,
29     pub container: String,
30     pub file_type: u8,
31     pub file_size: u32,
32     pub num_packages: u32,
33     pub bucket_offset: u32,
34     pub node_offset: u32,
35 }
36 
37 /// Implement debug print trait for header
38 impl fmt::Debug for PackageTableHeader {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result39     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40         writeln!(
41             f,
42             "Version: {}, Container: {}, File Type: {:?}, File Size: {}",
43             self.version,
44             self.container,
45             StorageFileType::try_from(self.file_type),
46             self.file_size
47         )?;
48         writeln!(
49             f,
50             "Num of Packages: {}, Bucket Offset:{}, Node Offset: {}",
51             self.num_packages, self.bucket_offset, self.node_offset
52         )?;
53         Ok(())
54     }
55 }
56 
57 impl PackageTableHeader {
58     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>59     pub fn into_bytes(&self) -> Vec<u8> {
60         let mut result = Vec::new();
61         result.extend_from_slice(&self.version.to_le_bytes());
62         let container_bytes = self.container.as_bytes();
63         result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes());
64         result.extend_from_slice(container_bytes);
65         result.extend_from_slice(&self.file_type.to_le_bytes());
66         result.extend_from_slice(&self.file_size.to_le_bytes());
67         result.extend_from_slice(&self.num_packages.to_le_bytes());
68         result.extend_from_slice(&self.bucket_offset.to_le_bytes());
69         result.extend_from_slice(&self.node_offset.to_le_bytes());
70         result
71     }
72 
73     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>74     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
75         let mut head = 0;
76         let table = Self {
77             version: read_u32_from_bytes(bytes, &mut head)?,
78             container: read_str_from_bytes(bytes, &mut head)?,
79             file_type: read_u8_from_bytes(bytes, &mut head)?,
80             file_size: read_u32_from_bytes(bytes, &mut head)?,
81             num_packages: read_u32_from_bytes(bytes, &mut head)?,
82             bucket_offset: read_u32_from_bytes(bytes, &mut head)?,
83             node_offset: read_u32_from_bytes(bytes, &mut head)?,
84         };
85         if table.file_type != StorageFileType::PackageMap as u8 {
86             return Err(AconfigStorageError::BytesParseFail(anyhow!(
87                 "binary file is not a package map"
88             )));
89         }
90         Ok(table)
91     }
92 }
93 
94 /// Package table node struct
95 #[derive(PartialEq)]
96 pub struct PackageTableNode {
97     pub package_name: String,
98     pub package_id: u32,
99     // The index of the first boolean flag in this aconfig package among all boolean
100     // flags in this container.
101     pub boolean_start_index: u32,
102     pub next_offset: Option<u32>,
103 }
104 
105 /// Implement debug print trait for node
106 impl fmt::Debug for PackageTableNode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result107     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108         writeln!(
109             f,
110             "Package: {}, Id: {}, Boolean flag start index: {}, Next: {:?}",
111             self.package_name, self.package_id, self.boolean_start_index, self.next_offset
112         )?;
113         Ok(())
114     }
115 }
116 
117 impl PackageTableNode {
118     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>119     pub fn into_bytes(&self) -> Vec<u8> {
120         let mut result = Vec::new();
121         let name_bytes = self.package_name.as_bytes();
122         result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
123         result.extend_from_slice(name_bytes);
124         result.extend_from_slice(&self.package_id.to_le_bytes());
125         result.extend_from_slice(&self.boolean_start_index.to_le_bytes());
126         result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes());
127         result
128     }
129 
130     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>131     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
132         let mut head = 0;
133         let node = Self {
134             package_name: read_str_from_bytes(bytes, &mut head)?,
135             package_id: read_u32_from_bytes(bytes, &mut head)?,
136             boolean_start_index: read_u32_from_bytes(bytes, &mut head)?,
137             next_offset: match read_u32_from_bytes(bytes, &mut head)? {
138                 0 => None,
139                 val => Some(val),
140             },
141         };
142         Ok(node)
143     }
144 
145     /// Get the bucket index for a package table node, defined it here so the
146     /// construction side (aconfig binary) and consumption side (flag read lib)
147     /// use the same method of hashing
find_bucket_index(package: &str, num_buckets: u32) -> u32148     pub fn find_bucket_index(package: &str, num_buckets: u32) -> u32 {
149         get_bucket_index(&package, num_buckets)
150     }
151 }
152 
153 /// Package table struct
154 #[derive(PartialEq)]
155 pub struct PackageTable {
156     pub header: PackageTableHeader,
157     pub buckets: Vec<Option<u32>>,
158     pub nodes: Vec<PackageTableNode>,
159 }
160 
161 /// Implement debug print trait for package table
162 impl fmt::Debug for PackageTable {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result163     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164         writeln!(f, "Header:")?;
165         write!(f, "{:?}", self.header)?;
166         writeln!(f, "Buckets:")?;
167         writeln!(f, "{:?}", self.buckets)?;
168         writeln!(f, "Nodes:")?;
169         for node in self.nodes.iter() {
170             write!(f, "{:?}", node)?;
171         }
172         Ok(())
173     }
174 }
175 
176 impl PackageTable {
177     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>178     pub fn into_bytes(&self) -> Vec<u8> {
179         [
180             self.header.into_bytes(),
181             self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(),
182             self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
183         ]
184         .concat()
185     }
186 
187     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>188     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
189         let header = PackageTableHeader::from_bytes(bytes)?;
190         let num_packages = header.num_packages;
191         let num_buckets = crate::get_table_size(num_packages)?;
192         let mut head = header.into_bytes().len();
193         let buckets = (0..num_buckets)
194             .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() {
195                 0 => None,
196                 val => Some(val),
197             })
198             .collect();
199         let nodes = (0..num_packages)
200             .map(|_| {
201                 let node = PackageTableNode::from_bytes(&bytes[head..])?;
202                 head += node.into_bytes().len();
203                 Ok(node)
204             })
205             .collect::<Result<Vec<_>, AconfigStorageError>>()
206             .map_err(|errmsg| {
207                 AconfigStorageError::BytesParseFail(anyhow!(
208                     "fail to parse package table: {}",
209                     errmsg
210                 ))
211             })?;
212 
213         let table = Self { header, buckets, nodes };
214         Ok(table)
215     }
216 }
217 
218 #[cfg(test)]
219 mod tests {
220     use super::*;
221     use crate::test_utils::create_test_package_table;
222 
223     #[test]
224     // this test point locks down the table serialization
test_serialization()225     fn test_serialization() {
226         let package_table = create_test_package_table();
227         let header: &PackageTableHeader = &package_table.header;
228         let reinterpreted_header = PackageTableHeader::from_bytes(&header.into_bytes());
229         assert!(reinterpreted_header.is_ok());
230         assert_eq!(header, &reinterpreted_header.unwrap());
231 
232         let nodes: &Vec<PackageTableNode> = &package_table.nodes;
233         for node in nodes.iter() {
234             let reinterpreted_node = PackageTableNode::from_bytes(&node.into_bytes()).unwrap();
235             assert_eq!(node, &reinterpreted_node);
236         }
237 
238         let package_table_bytes = package_table.into_bytes();
239         let reinterpreted_table = PackageTable::from_bytes(&package_table_bytes);
240         assert!(reinterpreted_table.is_ok());
241         assert_eq!(&package_table, &reinterpreted_table.unwrap());
242         assert_eq!(package_table_bytes.len() as u32, header.file_size);
243     }
244 
245     #[test]
246     // this test point locks down that version number should be at the top of serialized
247     // bytes
test_version_number()248     fn test_version_number() {
249         let package_table = create_test_package_table();
250         let bytes = &package_table.into_bytes();
251         let mut head = 0;
252         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
253         assert_eq!(version, 1);
254     }
255 
256     #[test]
257     // this test point locks down file type check
test_file_type_check()258     fn test_file_type_check() {
259         let mut package_table = create_test_package_table();
260         package_table.header.file_type = 123u8;
261         let error = PackageTable::from_bytes(&package_table.into_bytes()).unwrap_err();
262         assert_eq!(
263             format!("{:?}", error),
264             format!("BytesParseFail(binary file is not a package map)")
265         );
266     }
267 }
268