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