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 info module defines the flag info file format and methods for serialization
18 //! and deserialization
19 
20 use crate::{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 /// Flag info header struct
26 #[derive(PartialEq)]
27 pub struct FlagInfoHeader {
28     pub version: u32,
29     pub container: String,
30     pub file_type: u8,
31     pub file_size: u32,
32     pub num_flags: u32,
33     pub boolean_flag_offset: u32,
34 }
35 
36 /// Implement debug print trait for header
37 impl fmt::Debug for FlagInfoHeader {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result38     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39         writeln!(
40             f,
41             "Version: {}, Container: {}, File Type: {:?}, File Size: {}",
42             self.version,
43             self.container,
44             StorageFileType::try_from(self.file_type),
45             self.file_size
46         )?;
47         writeln!(
48             f,
49             "Num of Flags: {}, Boolean Flag Offset:{}",
50             self.num_flags, self.boolean_flag_offset
51         )?;
52         Ok(())
53     }
54 }
55 
56 impl FlagInfoHeader {
57     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>58     pub fn into_bytes(&self) -> Vec<u8> {
59         let mut result = Vec::new();
60         result.extend_from_slice(&self.version.to_le_bytes());
61         let container_bytes = self.container.as_bytes();
62         result.extend_from_slice(&(container_bytes.len() as u32).to_le_bytes());
63         result.extend_from_slice(container_bytes);
64         result.extend_from_slice(&self.file_type.to_le_bytes());
65         result.extend_from_slice(&self.file_size.to_le_bytes());
66         result.extend_from_slice(&self.num_flags.to_le_bytes());
67         result.extend_from_slice(&self.boolean_flag_offset.to_le_bytes());
68         result
69     }
70 
71     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>72     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
73         let mut head = 0;
74         let list = Self {
75             version: read_u32_from_bytes(bytes, &mut head)?,
76             container: read_str_from_bytes(bytes, &mut head)?,
77             file_type: read_u8_from_bytes(bytes, &mut head)?,
78             file_size: read_u32_from_bytes(bytes, &mut head)?,
79             num_flags: read_u32_from_bytes(bytes, &mut head)?,
80             boolean_flag_offset: read_u32_from_bytes(bytes, &mut head)?,
81         };
82         if list.file_type != StorageFileType::FlagInfo as u8 {
83             return Err(AconfigStorageError::BytesParseFail(anyhow!(
84                 "binary file is not a flag info file"
85             )));
86         }
87         Ok(list)
88     }
89 }
90 
91 /// bit field for flag info
92 #[derive(Clone, Debug, PartialEq, Eq)]
93 pub enum FlagInfoBit {
94     HasServerOverride = 1 << 0,
95     IsReadWrite = 1 << 1,
96     HasLocalOverride = 1 << 2,
97 }
98 
99 /// Flag info node struct
100 #[derive(PartialEq, Clone)]
101 pub struct FlagInfoNode {
102     pub attributes: u8,
103 }
104 
105 /// Implement debug print trait for node
106 impl fmt::Debug for FlagInfoNode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result107     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108         writeln!(
109             f,
110             "readwrite: {}, server override: {}, local override: {}",
111             self.attributes & (FlagInfoBit::IsReadWrite as u8) != 0,
112             self.attributes & (FlagInfoBit::HasServerOverride as u8) != 0,
113             self.attributes & (FlagInfoBit::HasLocalOverride as u8) != 0,
114         )?;
115         Ok(())
116     }
117 }
118 
119 impl FlagInfoNode {
120     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>121     pub fn into_bytes(&self) -> Vec<u8> {
122         let mut result = Vec::new();
123         result.extend_from_slice(&self.attributes.to_le_bytes());
124         result
125     }
126 
127     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>128     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
129         let mut head = 0;
130         let node = Self { attributes: read_u8_from_bytes(bytes, &mut head)? };
131         Ok(node)
132     }
133 
134     /// Create flag info node
create(is_flag_rw: bool) -> Self135     pub fn create(is_flag_rw: bool) -> Self {
136         Self { attributes: if is_flag_rw { FlagInfoBit::IsReadWrite as u8 } else { 0u8 } }
137     }
138 }
139 
140 /// Flag info list struct
141 #[derive(PartialEq)]
142 pub struct FlagInfoList {
143     pub header: FlagInfoHeader,
144     pub nodes: Vec<FlagInfoNode>,
145 }
146 
147 /// Implement debug print trait for flag info list
148 impl fmt::Debug for FlagInfoList {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result149     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150         writeln!(f, "Header:")?;
151         write!(f, "{:?}", self.header)?;
152         writeln!(f, "Nodes:")?;
153         for node in self.nodes.iter() {
154             write!(f, "{:?}", node)?;
155         }
156         Ok(())
157     }
158 }
159 
160 impl FlagInfoList {
161     /// Serialize to bytes
into_bytes(&self) -> Vec<u8>162     pub fn into_bytes(&self) -> Vec<u8> {
163         [
164             self.header.into_bytes(),
165             self.nodes.iter().map(|v| v.into_bytes()).collect::<Vec<_>>().concat(),
166         ]
167         .concat()
168     }
169 
170     /// Deserialize from bytes
from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError>171     pub fn from_bytes(bytes: &[u8]) -> Result<Self, AconfigStorageError> {
172         let header = FlagInfoHeader::from_bytes(bytes)?;
173         let num_flags = header.num_flags;
174         let mut head = header.into_bytes().len();
175         let nodes = (0..num_flags)
176             .map(|_| {
177                 let node = FlagInfoNode::from_bytes(&bytes[head..])?;
178                 head += node.into_bytes().len();
179                 Ok(node)
180             })
181             .collect::<Result<Vec<_>, AconfigStorageError>>()
182             .map_err(|errmsg| {
183                 AconfigStorageError::BytesParseFail(anyhow!(
184                     "fail to parse flag info list: {}",
185                     errmsg
186                 ))
187             })?;
188         let list = Self { header, nodes };
189         Ok(list)
190     }
191 }
192 
193 #[cfg(test)]
194 mod tests {
195     use super::*;
196     use crate::test_utils::create_test_flag_info_list;
197 
198     #[test]
199     // this test point locks down the value list serialization
test_serialization()200     fn test_serialization() {
201         let flag_info_list = create_test_flag_info_list();
202 
203         let header: &FlagInfoHeader = &flag_info_list.header;
204         let reinterpreted_header = FlagInfoHeader::from_bytes(&header.into_bytes());
205         assert!(reinterpreted_header.is_ok());
206         assert_eq!(header, &reinterpreted_header.unwrap());
207 
208         let nodes: &Vec<FlagInfoNode> = &flag_info_list.nodes;
209         for node in nodes.iter() {
210             let reinterpreted_node = FlagInfoNode::from_bytes(&node.into_bytes()).unwrap();
211             assert_eq!(node, &reinterpreted_node);
212         }
213 
214         let flag_info_bytes = flag_info_list.into_bytes();
215         let reinterpreted_info_list = FlagInfoList::from_bytes(&flag_info_bytes);
216         assert!(reinterpreted_info_list.is_ok());
217         assert_eq!(&flag_info_list, &reinterpreted_info_list.unwrap());
218         assert_eq!(flag_info_bytes.len() as u32, header.file_size);
219     }
220 
221     #[test]
222     // this test point locks down that version number should be at the top of serialized
223     // bytes
test_version_number()224     fn test_version_number() {
225         let flag_info_list = create_test_flag_info_list();
226         let bytes = &flag_info_list.into_bytes();
227         let mut head = 0;
228         let version = read_u32_from_bytes(bytes, &mut head).unwrap();
229         assert_eq!(version, 1);
230     }
231 
232     #[test]
233     // this test point locks down file type check
test_file_type_check()234     fn test_file_type_check() {
235         let mut flag_info_list = create_test_flag_info_list();
236         flag_info_list.header.file_type = 123u8;
237         let error = FlagInfoList::from_bytes(&flag_info_list.into_bytes()).unwrap_err();
238         assert_eq!(
239             format!("{:?}", error),
240             format!("BytesParseFail(binary file is not a flag info file)")
241         );
242     }
243 }
244