Skip to main content

verifyos_cli/parsers/
plist_reader.rs

1use 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}