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