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}