Skip to main content

android_abx/decode/
slice.rs

1use std::collections::HashMap;
2
3use crate::{AbxError, Attribute, AttributeValue, Event, MAGIC, Result, render_event};
4
5use super::grammar;
6use crate::InternedStr;
7
8pub(crate) fn check_magic(input: &[u8]) -> Result<()> {
9    let Some(&magic) = input.first_chunk::<4>() else {
10        return Err(AbxError::UnexpectedEof("magic header"));
11    };
12    if magic != MAGIC {
13        return Err(AbxError::InvalidMagic {
14            expected: MAGIC,
15            actual: magic,
16        });
17    }
18    Ok(())
19}
20
21/// A pull parser over an ABX document in memory.
22///
23/// Call [`next_event`](Self::next_event) until it returns `None`, or use a helper
24/// such as [`to_xml`](Self::to_xml) or [`find_attribute`](Self::find_attribute).
25/// Helpers consume events, so each call continues where the previous one
26/// stopped.
27///
28/// To read from a file or another [`Read`](std::io::Read) source, use
29/// [`AbxStreamParser`](crate::AbxStreamParser), which has the same methods.
30///
31/// # Examples
32///
33/// ```
34/// use android_abx::{AbxParser, Event};
35///
36/// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
37/// let mut parser = AbxParser::new(data)?;
38/// assert_eq!(parser.next_event()?, Some(Event::StartDocument));
39/// assert!(matches!(parser.next_event()?, Some(Event::StartTag { name, .. }) if name == "pkg"));
40/// # Ok::<(), android_abx::AbxError>(())
41/// ```
42#[derive(Debug)]
43pub struct AbxParser<'a> {
44    rest: &'a [u8],
45    pool: Vec<InternedStr>,
46}
47
48impl<'a> AbxParser<'a> {
49    /// Creates a parser over `input` and checks its header.
50    ///
51    /// # Errors
52    ///
53    /// Returns [`AbxError::UnexpectedEof`] if `input` is shorter than 4 bytes, or
54    /// [`AbxError::InvalidMagic`] if it does not start with [`MAGIC`].
55    pub fn new(input: &'a [u8]) -> Result<Self> {
56        check_magic(input)?;
57        Ok(AbxParser {
58            rest: &input[4..],
59            pool: Vec::with_capacity(32),
60        })
61    }
62
63    /// Returns `true` if all the input has been read.
64    pub fn is_empty(&self) -> bool {
65        self.rest.is_empty()
66    }
67
68    /// Reads the next event, or returns `None` at the end of the input.
69    ///
70    /// # Errors
71    ///
72    /// Returns an error if the input is truncated or malformed (unknown token,
73    /// invalid interned-string index, invalid UTF-8).
74    /// On error, the parser is left at the start of the failing event.
75    pub fn next_event(&mut self) -> Result<Option<Event>> {
76        if self.rest.is_empty() {
77            return Ok(None);
78        }
79        let mut input = self.rest;
80        let pool_len = self.pool.len();
81        match grammar::event(&mut input, &mut self.pool) {
82            Ok(ev) => {
83                self.rest = input;
84                Ok(Some(ev))
85            }
86            Err(e) => {
87                self.pool.truncate(pool_len);
88                Err(grammar::into_abx_error(e))
89            }
90        }
91    }
92
93    /// Reads all remaining events into a `Vec`.
94    ///
95    /// # Errors
96    ///
97    /// Returns an error if the input is truncated or malformed (unknown token,
98    /// invalid interned-string index, invalid UTF-8).
99    pub fn collect_events(&mut self) -> Result<Vec<Event>> {
100        let mut events = Vec::new();
101        while let Some(ev) = self.next_event()? {
102            events.push(ev);
103        }
104        Ok(events)
105    }
106
107    /// Returns the value of attribute `attr` on the next `<element>` tag that has it.
108    ///
109    /// Events are consumed up to and including the matching tag. Returns `Ok(None)`
110    /// if the document ends first.
111    ///
112    /// # Errors
113    ///
114    /// Returns an error if the input is truncated or malformed (unknown token,
115    /// invalid interned-string index, invalid UTF-8).
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use android_abx::{AbxParser, AttributeValue};
121    ///
122    /// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
123    /// let mut parser = AbxParser::new(data)?;
124    /// let name = parser.find_attribute("pkg", "name")?;
125    /// assert_eq!(name, Some(AttributeValue::String("com.example.chat".into())));
126    /// # Ok::<(), android_abx::AbxError>(())
127    /// ```
128    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Result<Option<AttributeValue>> {
129        loop {
130            match self.next_event()? {
131                Some(Event::StartTag { name, attributes }) if name == element => {
132                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
133                        return Ok(Some(a.value));
134                    }
135                }
136                Some(Event::EndDocument) | None => return Ok(None),
137                _ => {}
138            }
139        }
140    }
141
142    /// Returns the value of attribute `attr` on every remaining `<element>` tag.
143    ///
144    /// Tags without `attr` are skipped. Consumes the rest of the document.
145    ///
146    /// # Errors
147    ///
148    /// Returns an error if the input is truncated or malformed (unknown token,
149    /// invalid interned-string index, invalid UTF-8).
150    pub fn find_all_attributes(
151        &mut self,
152        element: &str,
153        attr: &str,
154    ) -> Result<Vec<AttributeValue>> {
155        let mut out = Vec::new();
156        while let Some(ev) = self.next_event()? {
157            if let Event::StartTag { name, attributes } = ev
158                && name == element
159            {
160                out.extend(
161                    attributes
162                        .into_iter()
163                        .filter(|a| a.name == attr)
164                        .map(|a| a.value),
165                );
166            }
167        }
168        Ok(out)
169    }
170
171    /// Returns the attributes of the next `<element>` tag.
172    ///
173    /// Events are consumed up to and including the matching tag. Returns `Ok(None)`
174    /// if the document ends first.
175    ///
176    /// # Errors
177    ///
178    /// Returns an error if the input is truncated or malformed (unknown token,
179    /// invalid interned-string index, invalid UTF-8).
180    pub fn attributes_of(&mut self, element: &str) -> Result<Option<Vec<Attribute>>> {
181        loop {
182            match self.next_event()? {
183                Some(Event::StartTag { name, attributes }) if name == element => {
184                    return Ok(Some(attributes));
185                }
186                Some(Event::EndDocument) | None => return Ok(None),
187                _ => {}
188            }
189        }
190    }
191
192    /// Returns the attributes of every remaining `<element>` tag.
193    ///
194    /// Consumes the rest of the document.
195    ///
196    /// # Errors
197    ///
198    /// Returns an error if the input is truncated or malformed (unknown token,
199    /// invalid interned-string index, invalid UTF-8).
200    pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
201        let mut out = Vec::new();
202        while let Some(ev) = self.next_event()? {
203            if let Event::StartTag { name, attributes } = ev
204                && name == element
205            {
206                out.push(attributes);
207            }
208        }
209        Ok(out)
210    }
211
212    /// Renders the remaining events as an XML string.
213    ///
214    /// The output starts with an `<?xml ...?>` declaration. Text and attribute values
215    /// are escaped; empty elements are written as an opening and a closing tag.
216    ///
217    /// # Errors
218    ///
219    /// Returns an error if the input is truncated or malformed (unknown token,
220    /// invalid interned-string index, invalid UTF-8).
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// use android_abx::AbxParser;
226    ///
227    /// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
228    /// let xml = AbxParser::new(data)?.to_xml()?;
229    /// assert!(xml.ends_with(r#"<pkg name="com.example.chat" version="3" flags="1"></pkg>"#));
230    /// # Ok::<(), android_abx::AbxError>(())
231    /// ```
232    pub fn to_xml(&mut self) -> Result<String> {
233        let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
234        while let Some(ev) = self.next_event()? {
235            if matches!(ev, Event::EndDocument) {
236                break;
237            }
238            render_event(&ev, &mut buf);
239        }
240        Ok(buf)
241    }
242
243    /// Writes the remaining events as XML to `writer`.
244    ///
245    /// Same output as [`to_xml`](Self::to_xml), without building the whole string
246    /// in memory.
247    ///
248    /// # Errors
249    ///
250    /// Returns an error if the input is truncated or malformed (unknown token,
251    /// invalid interned-string index, invalid UTF-8).
252    /// Also returns [`AbxError::Io`](crate::AbxError::Io) if reading or writing fails.
253    pub fn write_xml(&mut self, writer: &mut impl std::io::Write) -> Result<()> {
254        writer.write_all(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
255        let mut tmp = String::new();
256        while let Some(ev) = self.next_event()? {
257            if matches!(ev, Event::EndDocument) {
258                break;
259            }
260            tmp.clear();
261            render_event(&ev, &mut tmp);
262            writer.write_all(tmp.as_bytes())?;
263        }
264        Ok(())
265    }
266
267    /// Deserializes the next `<element>` into `T`.
268    ///
269    /// Events are consumed up to and including the element's closing tag. Returns
270    /// `Ok(None)` if the document ends first. See
271    /// [Deserializing with serde](crate#deserializing-with-serde) for how fields are
272    /// matched.
273    ///
274    /// # Errors
275    ///
276    /// Returns a parse error if the input is malformed, or
277    /// [`AbxError::Deserialization`](crate::AbxError::Deserialization) if the element
278    /// does not match `T`.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use android_abx::AbxParser;
284    /// use serde::Deserialize;
285    ///
286    /// #[derive(Deserialize)]
287    /// struct Permission {
288    ///     name: String,
289    /// }
290    ///
291    /// #[derive(Deserialize)]
292    /// struct Pkg {
293    ///     name: String,
294    ///     description: String,
295    ///     permission: Vec<Permission>,
296    /// }
297    ///
298    /// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/nested_permissions.abx"));
299    /// let mut parser = AbxParser::new(data)?;
300    /// let pkg: Pkg = parser.deserialize_next("pkg")?.unwrap();
301    /// assert_eq!(pkg.name, "com.example.chat");
302    /// assert_eq!(pkg.description, "A chat app");
303    /// assert_eq!(pkg.permission.len(), 2);
304    /// # Ok::<(), android_abx::AbxError>(())
305    /// ```
306    #[cfg(feature = "serde")]
307    pub fn deserialize_next<T: serde::de::DeserializeOwned>(
308        &mut self,
309        element: &str,
310    ) -> Result<Option<T>> {
311        crate::de::find_and_consume_element(self, element)
312    }
313
314    /// Deserializes every remaining `<element>` into a `Vec<T>`.
315    ///
316    /// # Errors
317    ///
318    /// Same as [`deserialize_next`](Self::deserialize_next).
319    #[cfg(feature = "serde")]
320    pub fn deserialize_all<T: serde::de::DeserializeOwned>(
321        &mut self,
322        element: &str,
323    ) -> Result<Vec<T>> {
324        let mut out = Vec::new();
325        while let Some(item) = self.deserialize_next(element)? {
326            out.push(item);
327        }
328        Ok(out)
329    }
330
331    /// Collects the attributes of every remaining tag, grouped by tag name.
332    ///
333    /// Values are rendered with [`AttributeValue::as_str`](crate::AttributeValue::as_str).
334    /// Text and nesting are discarded.
335    ///
336    /// # Errors
337    ///
338    /// Returns an error if the input is truncated or malformed (unknown token,
339    /// invalid interned-string index, invalid UTF-8).
340    pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
341        let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
342        while let Some(ev) = self.next_event()? {
343            if let Event::StartTag { name, attributes } = ev {
344                let entry = map.entry(name.into()).or_default();
345                let mut attrs = HashMap::new();
346                for attr in attributes {
347                    attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
348                }
349                entry.push(attrs);
350            }
351        }
352        Ok(map)
353    }
354}
355
356/// An ABX document that owns its bytes.
357///
358/// Useful to keep a document in a struct without a lifetime. Call
359/// [`parser`](Self::parser) to read it.
360///
361/// # Examples
362///
363/// ```
364/// use android_abx::AbxParserOwned;
365///
366/// # let data = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/simple_pkg.abx"));
367/// let doc = AbxParserOwned::new(data.to_vec())?;
368/// let xml = doc.parser()?.to_xml()?;
369/// assert!(xml.contains("<pkg "));
370/// # Ok::<(), android_abx::AbxError>(())
371/// ```
372#[derive(Debug)]
373pub struct AbxParserOwned {
374    data: Vec<u8>,
375}
376
377impl AbxParserOwned {
378    /// Takes ownership of `data` and checks its header.
379    ///
380    /// # Errors
381    ///
382    /// Returns [`AbxError::UnexpectedEof`] if `data` is shorter than 4 bytes, or
383    /// [`AbxError::InvalidMagic`] if it does not start with [`MAGIC`].
384    pub fn new(data: Vec<u8>) -> Result<Self> {
385        check_magic(&data)?;
386        Ok(Self { data })
387    }
388
389    /// Returns a parser positioned at the start of the document.
390    ///
391    /// # Errors
392    ///
393    /// Never fails in practice: the header was already checked by
394    /// [`new`](Self::new).
395    pub fn parser(&self) -> Result<AbxParser<'_>> {
396        AbxParser::new(&self.data)
397    }
398}