verifyos_cli/parsers/
plist_reader.rs1use plist::Value;
2use std::path::Path;
3
4#[derive(Debug, thiserror::Error)]
5pub enum PlistError {
6 #[error("Plist Error: {0}")]
7 ParseError(#[from] plist::Error),
8 #[error("Not a dictionary")]
9 NotADictionary,
10}
11
12#[derive(Debug, Clone)]
13pub struct InfoPlist {
14 pub root: Value,
15}
16
17impl InfoPlist {
18 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, PlistError> {
19 let value = Value::from_file(path)?;
20 if value.as_dictionary().is_none() {
21 return Err(PlistError::NotADictionary);
22 }
23 Ok(Self { root: value })
24 }
25
26 pub fn from_bytes(bytes: &[u8]) -> Result<Self, PlistError> {
27 let value = Value::from_reader(std::io::Cursor::new(bytes))?;
28 if value.as_dictionary().is_none() {
29 return Err(PlistError::NotADictionary);
30 }
31 Ok(Self { root: value })
32 }
33
34 pub fn from_dictionary(dict: plist::Dictionary) -> Self {
35 Self {
36 root: Value::Dictionary(dict),
37 }
38 }
39
40 pub fn get_string(&self, key: &str) -> Option<&str> {
41 self.root
42 .as_dictionary()
43 .and_then(|dict| dict.get(key))
44 .and_then(|v| v.as_string())
45 }
46
47 pub fn get_bool(&self, key: &str) -> Option<bool> {
48 self.root
49 .as_dictionary()
50 .and_then(|dict| dict.get(key))
51 .and_then(|v| v.as_boolean())
52 }
53
54 pub fn has_key(&self, key: &str) -> bool {
55 self.root
56 .as_dictionary()
57 .map(|dict| dict.contains_key(key))
58 .unwrap_or(false)
59 }
60
61 pub fn get_dictionary(&self, key: &str) -> Option<&plist::Dictionary> {
62 self.root
63 .as_dictionary()
64 .and_then(|dict| dict.get(key))
65 .and_then(|v| v.as_dictionary())
66 }
67
68 pub fn get_value(&self, key: &str) -> Option<&Value> {
69 self.root.as_dictionary().and_then(|dict| dict.get(key))
70 }
71
72 pub fn get_array_strings(&self, key: &str) -> Option<Vec<String>> {
73 self.root
74 .as_dictionary()
75 .and_then(|dict| dict.get(key))
76 .and_then(|v| v.as_array())
77 .map(|arr| {
78 arr.iter()
79 .filter_map(|v| v.as_string().map(|s| s.to_string()))
80 .collect()
81 })
82 }
83}