1 /* 2 * Copyright (C) 2024 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 //! flag table module defines the flag table file format and methods for serialization 18 //! and deserialization 19 20 use crate::{ 21 get_bucket_index, read_str_from_bytes, read_u16_from_bytes, read_u32_from_bytes, 22 read_u8_from_bytes, 23 }; 24 use crate::{AconfigStorageError, StorageFileType, StoredFlagType}; 25 use anyhow::anyhow; 26 use std::fmt; 27 28 /// Flag table header struct 29 #[derive(PartialEq)] 30 pub struct FlagTableHeader { 31 pub version: u32, 32 pub container: String, 33 pub file_type: u8, 34 pub file_size: u32, 35 pub num_flags: u32, 36 pub bucket_offset: u32, 37 pub node_offset: u32, 38 } 39 40 /// Implement debug print trait for header 41 impl fmt::Debug for FlagTableHeader { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 writeln!( 44 f, 45 "Version: {}, Container: {}, File Type: {:?}, File Size: {}", 46 self.version, 47 self.container, 48 StorageFileType::try_from(self.file_type), 49 self.file_size 50 )?; 51 writeln!( 52 f, 53 "Num of Flags: {}, Bucket Offset:{}, Node Offset: {}", 54 self.num_flags, self.bucket_offset, self.node_offset 55 )?; 56 Ok(()) 57 } 58 } 59 60 impl FlagTableHeader { 61 /// Serialize to bytes into_bytes(&self) -> Vec<u8>62 pub fn into_bytes(&self) -> Vec<u8> { 63 let mut result = Vec::new(); 64 result.extend_from_slice(&self.version.to_le_bytes()); 65 let container_bytes = self.container.as_bytes(); 66 result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes()); 67 result.extend_from_slice(container_bytes); 68 result.extend_from_slice(&self.file_type.to_le_bytes()); 69 result.extend_from_slice(&self.file_size.to_le_bytes()); 70 result.extend_from_slice(&self.num_flags.to_le_bytes()); 71 result.extend_from_slice(&self.bucket_offset.to_le_bytes()); 72 result.extend_from_slice(&self.node_offset.to_le_bytes()); 73 result 74 } 75 76 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>77 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 78 let mut head = 0; 79 let table = Self { 80 version: read_u32_from_bytes(bytes, &mut head)?, 81 container: read_str_from_bytes(bytes, &mut head)?, 82 file_type: read_u8_from_bytes(bytes, &mut head)?, 83 file_size: read_u32_from_bytes(bytes, &mut head)?, 84 num_flags: read_u32_from_bytes(bytes, &mut head)?, 85 bucket_offset: read_u32_from_bytes(bytes, &mut head)?, 86 node_offset: read_u32_from_bytes(bytes, &mut head)?, 87 }; 88 if table.file_type != StorageFileType::FlagMap as u8 { 89 return Err(AconfigStorageError::BytesParseFail(anyhow!( 90 "binary file is not a flag map" 91 ))); 92 } 93 Ok(table) 94 } 95 } 96 97 /// Flag table node struct 98 #[derive(PartialEq, Clone)] 99 pub struct FlagTableNode { 100 pub package_id: u32, 101 pub flag_name: String, 102 pub flag_type: StoredFlagType, 103 // within package flag index of this flag type 104 pub flag_index: u16, 105 pub next_offset: Option<u32>, 106 } 107 108 /// Implement debug print trait for node 109 impl fmt::Debug for FlagTableNode { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 111 writeln!( 112 f, 113 "Package Id: {}, Flag: {}, Type: {:?}, Index: {}, Next: {:?}", 114 self.package_id, self.flag_name, self.flag_type, self.flag_index, self.next_offset 115 )?; 116 Ok(()) 117 } 118 } 119 120 impl FlagTableNode { 121 /// Serialize to bytes into_bytes(&self) -> Vec<u8>122 pub fn into_bytes(&self) -> Vec<u8> { 123 let mut result = Vec::new(); 124 result.extend_from_slice(&self.package_id.to_le_bytes()); 125 let name_bytes = self.flag_name.as_bytes(); 126 result.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes()); 127 result.extend_from_slice(name_bytes); 128 result.extend_from_slice(&(self.flag_type as u16).to_le_bytes()); 129 result.extend_from_slice(&self.flag_index.to_le_bytes()); 130 result.extend_from_slice(&self.next_offset.unwrap_or(0).to_le_bytes()); 131 result 132 } 133 134 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>135 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 136 let mut head = 0; 137 let node = Self { 138 package_id: read_u32_from_bytes(bytes, &mut head)?, 139 flag_name: read_str_from_bytes(bytes, &mut head)?, 140 flag_type: StoredFlagType::try_from(read_u16_from_bytes(bytes, &mut head)?)?, 141 flag_index: read_u16_from_bytes(bytes, &mut head)?, 142 next_offset: match read_u32_from_bytes(bytes, &mut head)? { 143 0 => None, 144 val => Some(val), 145 }, 146 }; 147 Ok(node) 148 } 149 150 /// Calculate node bucket index find_bucket_index(package_id: u32, flag_name: &str, num_buckets: u32) -> u32151 pub fn find_bucket_index(package_id: u32, flag_name: &str, num_buckets: u32) -> u32 { 152 let full_flag_name = package_id.to_string() + "/" + flag_name; 153 get_bucket_index(&full_flag_name, num_buckets) 154 } 155 } 156 157 #[derive(PartialEq)] 158 pub struct FlagTable { 159 pub header: FlagTableHeader, 160 pub buckets: Vec<Option<u32>>, 161 pub nodes: Vec<FlagTableNode>, 162 } 163 164 /// Implement debug print trait for flag table 165 impl fmt::Debug for FlagTable { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 167 writeln!(f, "Header:")?; 168 write!(f, "{:?}", self.header)?; 169 writeln!(f, "Buckets:")?; 170 writeln!(f, "{:?}", self.buckets)?; 171 writeln!(f, "Nodes:")?; 172 for node in self.nodes.iter() { 173 write!(f, "{:?}", node)?; 174 } 175 Ok(()) 176 } 177 } 178 179 /// Flag table struct 180 impl FlagTable { 181 /// Serialize to bytes into_bytes(&self) -> Vec<u8>182 pub fn into_bytes(&self) -> Vec<u8> { 183 [ 184 self.header.into_bytes(), 185 self.buckets.iter().map(|v| v.unwrap_or(0).to_le_bytes()).collect::<Vec<_>>().concat(), 186 self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(), 187 ] 188 .concat() 189 } 190 191 /// Deserialize from bytes from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>192 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> { 193 let header = FlagTableHeader::from_bytes(bytes)?; 194 let num_flags = header.num_flags; 195 let num_buckets = crate::get_table_size(num_flags)?; 196 let mut head = header.into_bytes().len(); 197 let buckets = (0..num_buckets) 198 .map(|_| match read_u32_from_bytes(bytes, &mut head).unwrap() { 199 0 => None, 200 val => Some(val), 201 }) 202 .collect(); 203 let nodes = (0..num_flags) 204 .map(|_| { 205 let node = FlagTableNode::from_bytes(&bytes[head..])?; 206 head += node.into_bytes().len(); 207 Ok(node) 208 }) 209 .collect::<Result<Vec<_>, AconfigStorageError>>() 210 .map_err(|errmsg| { 211 AconfigStorageError::BytesParseFail(anyhow!("fail to parse flag table: {}", errmsg)) 212 })?; 213 214 let table = Self { header, buckets, nodes }; 215 Ok(table) 216 } 217 } 218 219 #[cfg(test)] 220 mod tests { 221 use super::*; 222 use crate::test_utils::create_test_flag_table; 223 224 #[test] 225 // this test point locks down the table serialization test_serialization()226 fn test_serialization() { 227 let flag_table = create_test_flag_table(); 228 229 let header: &FlagTableHeader = &flag_table.header; 230 let reinterpreted_header = FlagTableHeader::from_bytes(&header.into_bytes()); 231 assert!(reinterpreted_header.is_ok()); 232 assert_eq!(header, &reinterpreted_header.unwrap()); 233 234 let nodes: &Vec<FlagTableNode> = &flag_table.nodes; 235 for node in nodes.iter() { 236 let reinterpreted_node = FlagTableNode::from_bytes(&node.into_bytes()).unwrap(); 237 assert_eq!(node, &reinterpreted_node); 238 } 239 240 let flag_table_bytes = flag_table.into_bytes(); 241 let reinterpreted_table = FlagTable::from_bytes(&flag_table_bytes); 242 assert!(reinterpreted_table.is_ok()); 243 assert_eq!(&flag_table, &reinterpreted_table.unwrap()); 244 assert_eq!(flag_table_bytes.len() as u32, header.file_size); 245 } 246 247 #[test] 248 // this test point locks down that version number should be at the top of serialized 249 // bytes test_version_number()250 fn test_version_number() { 251 let flag_table = create_test_flag_table(); 252 let bytes = &flag_table.into_bytes(); 253 let mut head = 0; 254 let version = read_u32_from_bytes(bytes, &mut head).unwrap(); 255 assert_eq!(version, 1); 256 } 257 258 #[test] 259 // this test point locks down file type check test_file_type_check()260 fn test_file_type_check() { 261 let mut flag_table = create_test_flag_table(); 262 flag_table.header.file_type = 123u8; 263 let error = FlagTable::from_bytes(&flag_table.into_bytes()).unwrap_err(); 264 assert_eq!( 265 format!("{:?}", error), 266 format!("BytesParseFail(binary file is not a flag map)") 267 ); 268 } 269 } 270