• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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