Skip to main content

abx/decode/
slice.rs

1//! [`AbxParser`] — zero-allocation pull parser over an in-memory `&[u8]` —
2//! and [`AbxParserOwned`], a heap-owning wrapper around it.
3//!
4//! The public surface is intentionally identical to
5//! [`AbxStreamParser`](crate::AbxStreamParser) so the two types are
6//! interchangeable; just swap the constructor.
7
8use std::collections::HashMap;
9
10use nom::{
11    IResult, Parser,
12    bytes::complete::take,
13    number::complete::{be_f32, be_f64, be_i32, be_i64, be_u8, be_u16},
14};
15
16use crate::{
17    AbxError, Attribute, AttributeValue, CMD_ATTRIBUTE, CMD_CDSECT, CMD_COMMENT, CMD_DOCDECL,
18    CMD_END_DOCUMENT, CMD_END_TAG, CMD_ENTITY_REF, CMD_IGNORABLE_WHITESPACE,
19    CMD_PROCESSING_INSTRUCTION, CMD_START_DOCUMENT, CMD_START_TAG, CMD_TEXT, Event, MAGIC, Result,
20    TYPE_BOOLEAN_FALSE, TYPE_BOOLEAN_TRUE, TYPE_BYTES_BASE64, TYPE_BYTES_HEX, TYPE_DOUBLE,
21    TYPE_FLOAT, TYPE_INT, TYPE_INT_HEX, TYPE_LONG, TYPE_LONG_HEX, TYPE_NULL, TYPE_STRING,
22    TYPE_STRING_INTERNED, render_event,
23};
24
25use crate::INTERNED_NEW;
26use crate::InternedStr;
27
28fn parse_utf_string(input: &[u8]) -> IResult<&[u8], String> {
29    let (input, len) = be_u16(input)?;
30    let (input, bytes) = take(len).parse(input)?;
31    let s = std::str::from_utf8(bytes)
32        .map_err(|_| {
33            nom::Err::Failure(nom::error::Error::new(input, nom::error::ErrorKind::Verify))
34        })?
35        .to_owned();
36    Ok((input, s))
37}
38
39fn parse_bytes_blob(input: &[u8]) -> IResult<&[u8], Vec<u8>> {
40    let (input, len) = be_u16(input)?;
41    let (input, bytes) = take(len).parse(input)?;
42    Ok((input, bytes.to_vec()))
43}
44
45/// Zero-allocation pull parser that works on an in-memory `&[u8]`.
46///
47/// Advance through the document with [`next_event`](AbxParser::next_event) or
48/// use one of the higher-level helpers.
49#[derive(Debug)]
50pub struct AbxParser<'a> {
51    rest: &'a [u8],
52    pool: Vec<InternedStr>,
53}
54
55impl<'a> AbxParser<'a> {
56    /// Create a parser, validating the 4-byte magic header.
57    pub fn new(input: &'a [u8]) -> Result<Self> {
58        if input.len() < 4 {
59            return Err(AbxError::UnexpectedEof("magic header"));
60        }
61        let magic: [u8; 4] = input[..4].try_into().unwrap();
62        if magic != MAGIC {
63            return Err(AbxError::InvalidMagic {
64                expected: MAGIC,
65                actual: magic,
66            });
67        }
68        Ok(AbxParser {
69            rest: &input[4..],
70            pool: Vec::with_capacity(32),
71        })
72    }
73
74    /// `true` when no more bytes remain.
75    pub fn is_empty(&self) -> bool {
76        self.rest.is_empty()
77    }
78
79    // -- internal helpers --
80
81    fn run<F, T>(&mut self, f: F) -> Result<T>
82    where
83        F: Fn(&'a [u8]) -> IResult<&'a [u8], T>,
84    {
85        let (rest, val) = f(self.rest).map_err(|e| AbxError::Nom(format!("{e:?}")))?;
86        self.rest = rest;
87        Ok(val)
88    }
89
90    fn read_u8(&mut self) -> Result<u8> {
91        self.run(be_u8)
92    }
93    fn read_u16(&mut self) -> Result<u16> {
94        self.run(be_u16)
95    }
96    fn read_i32(&mut self) -> Result<i32> {
97        self.run(be_i32)
98    }
99    fn read_i64(&mut self) -> Result<i64> {
100        self.run(be_i64)
101    }
102    fn read_f32(&mut self) -> Result<f32> {
103        self.run(be_f32)
104    }
105    fn read_f64(&mut self) -> Result<f64> {
106        self.run(be_f64)
107    }
108
109    fn read_utf(&mut self) -> Result<String> {
110        self.run(parse_utf_string)
111    }
112    fn read_bytes_blob(&mut self) -> Result<Vec<u8>> {
113        self.run(parse_bytes_blob)
114    }
115
116    /// Read an interned string. Every occurrence after the first is a
117    /// back-reference into `pool`, resolved with `InternedStr::clone` (a
118    /// refcount bump) rather than a fresh allocation and copy.
119    fn read_interned(&mut self) -> Result<InternedStr> {
120        let idx = self.read_u16()?;
121        if idx == INTERNED_NEW {
122            let s: InternedStr = self.read_utf()?.into();
123            self.pool.push(s.clone());
124            Ok(s)
125        } else {
126            self.pool
127                .get(idx as usize)
128                .cloned()
129                .ok_or(AbxError::BadInternedIndex(idx))
130        }
131    }
132
133    fn read_attr_value(&mut self, type_nibble: u8) -> Result<AttributeValue> {
134        match type_nibble {
135            TYPE_NULL => Ok(AttributeValue::Null),
136            TYPE_STRING => Ok(AttributeValue::String(self.read_utf()?)),
137            TYPE_STRING_INTERNED => Ok(AttributeValue::String(self.read_interned()?.to_string())),
138            TYPE_BYTES_HEX => Ok(AttributeValue::BytesHex(self.read_bytes_blob()?)),
139            TYPE_BYTES_BASE64 => Ok(AttributeValue::BytesBase64(self.read_bytes_blob()?)),
140            TYPE_INT => Ok(AttributeValue::Int(self.read_i32()?)),
141            TYPE_INT_HEX => Ok(AttributeValue::IntHex(self.read_i32()? as u32)),
142            TYPE_LONG => Ok(AttributeValue::Long(self.read_i64()?)),
143            TYPE_LONG_HEX => Ok(AttributeValue::LongHex(self.read_i64()? as u64)),
144            TYPE_FLOAT => Ok(AttributeValue::Float(self.read_f32()?)),
145            TYPE_DOUBLE => Ok(AttributeValue::Double(self.read_f64()?)),
146            TYPE_BOOLEAN_TRUE => Ok(AttributeValue::Boolean(true)),
147            TYPE_BOOLEAN_FALSE => Ok(AttributeValue::Boolean(false)),
148            other => Err(AbxError::UnknownAttributeType(other)),
149        }
150    }
151
152    // -- public event API --
153
154    /// Pull the next [`Event`].  Returns `None` at end of input.
155    pub fn next_event(&mut self) -> Result<Option<Event>> {
156        if self.rest.is_empty() {
157            return Ok(None);
158        }
159
160        let token = self.read_u8()?;
161        let cmd = token & 0x0F;
162        let type_nibble = token & 0xF0;
163
164        let event = match cmd {
165            CMD_START_DOCUMENT => Event::StartDocument,
166            CMD_END_DOCUMENT => return Ok(Some(Event::EndDocument)),
167
168            CMD_START_TAG => {
169                let name = self.read_interned()?;
170                let mut attributes = Vec::new();
171                loop {
172                    if self.rest.is_empty() {
173                        break;
174                    }
175                    let next = self.rest[0];
176                    if (next & 0x0F) != CMD_ATTRIBUTE {
177                        break;
178                    }
179                    self.rest = &self.rest[1..];
180                    let attr_type = next & 0xF0;
181                    let attr_name = self.read_interned()?;
182                    let attr_value = self.read_attr_value(attr_type)?;
183                    attributes.push(Attribute {
184                        name: attr_name,
185                        value: attr_value,
186                    });
187                }
188                Event::StartTag { name, attributes }
189            }
190
191            CMD_END_TAG => Event::EndTag {
192                name: self.read_interned()?,
193            },
194
195            CMD_TEXT => Event::Text(if type_nibble == TYPE_STRING {
196                self.read_utf()?
197            } else {
198                String::new()
199            }),
200            CMD_CDSECT => Event::CdataSection(if type_nibble == TYPE_STRING {
201                self.read_utf()?
202            } else {
203                String::new()
204            }),
205            CMD_ENTITY_REF => Event::EntityReference(if type_nibble == TYPE_STRING {
206                self.read_utf()?
207            } else {
208                String::new()
209            }),
210            CMD_IGNORABLE_WHITESPACE => Event::IgnorableWhitespace(if type_nibble == TYPE_STRING {
211                self.read_utf()?
212            } else {
213                String::new()
214            }),
215            CMD_PROCESSING_INSTRUCTION => {
216                Event::ProcessingInstruction(if type_nibble == TYPE_STRING {
217                    self.read_utf()?
218                } else {
219                    String::new()
220                })
221            }
222            CMD_COMMENT => Event::Comment(if type_nibble == TYPE_STRING {
223                self.read_utf()?
224            } else {
225                String::new()
226            }),
227            CMD_DOCDECL => Event::DocDecl(if type_nibble == TYPE_STRING {
228                self.read_utf()?
229            } else {
230                String::new()
231            }),
232
233            other => return Err(AbxError::UnknownCommand(other)),
234        };
235
236        Ok(Some(event))
237    }
238
239    // -- convenience API (mirrors AbxStreamParser) --
240
241    /// Drain all remaining events into a `Vec`.
242    pub fn collect_events(&mut self) -> Result<Vec<Event>> {
243        let mut events = Vec::new();
244        while let Some(ev) = self.next_event()? {
245            events.push(ev);
246        }
247        Ok(events)
248    }
249
250    /// Return the value of the first matching `attr_name` inside any
251    /// `<element_name>` in the remaining stream.
252    pub fn find_attribute(&mut self, element: &str, attr: &str) -> Option<AttributeValue> {
253        loop {
254            match self.next_event().ok()? {
255                Some(Event::StartTag { name, attributes }) if name == element => {
256                    if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
257                        return Some(a.value);
258                    }
259                }
260                Some(Event::EndDocument) | None => return None,
261                _ => {}
262            }
263        }
264    }
265
266    /// All values of `attr_name` found in `<element_name>` tags.
267    pub fn find_all_attributes(
268        &mut self,
269        element: &str,
270        attr: &str,
271    ) -> Result<Vec<AttributeValue>> {
272        let mut out = Vec::new();
273        while let Some(ev) = self.next_event()? {
274            if let Event::StartTag { name, attributes } = ev
275                && name == element
276            {
277                out.extend(
278                    attributes
279                        .into_iter()
280                        .filter(|a| a.name == attr)
281                        .map(|a| a.value),
282                );
283            }
284        }
285        Ok(out)
286    }
287
288    /// Attributes of the first `<element_name>` tag.
289    pub fn attributes_of(&mut self, element: &str) -> Option<Vec<Attribute>> {
290        loop {
291            match self.next_event().ok()? {
292                Some(Event::StartTag { name, attributes }) if name == element => {
293                    return Some(attributes);
294                }
295                Some(Event::EndDocument) | None => return None,
296                _ => {}
297            }
298        }
299    }
300
301    /// Attributes of every `<element_name>` tag.
302    pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
303        let mut out = Vec::new();
304        while let Some(ev) = self.next_event()? {
305            if let Event::StartTag { name, attributes } = ev
306                && name == element
307            {
308                out.push(attributes);
309            }
310        }
311        Ok(out)
312    }
313
314    /// Render the rest of the document as an XML string.
315    pub fn to_xml(&mut self) -> Result<String> {
316        let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
317        while let Some(ev) = self.next_event()? {
318            if matches!(ev, Event::EndDocument) {
319                break;
320            }
321            render_event(&ev, &mut buf);
322        }
323        Ok(buf)
324    }
325
326    /// Find the next `<element>`, deserialize its attributes (and direct
327    /// text content, via a `#[serde(rename = "$text")]` field) into `T`,
328    /// then skip past its matching end tag. `Ok(None)` at end of document.
329    #[cfg(feature = "serialize")]
330    pub fn deserialize_next<T: serde::de::DeserializeOwned>(
331        &mut self,
332        element: &str,
333    ) -> Result<Option<T>> {
334        crate::de::find_and_consume_element(self, element)
335    }
336
337    /// Deserialize every remaining `<element>` into a `Vec<T>`.
338    #[cfg(feature = "serialize")]
339    pub fn deserialize_all<T: serde::de::DeserializeOwned>(
340        &mut self,
341        element: &str,
342    ) -> Result<Vec<T>> {
343        let mut out = Vec::new();
344        while let Some(item) = self.deserialize_next(element)? {
345            out.push(item);
346        }
347        Ok(out)
348    }
349
350    /// Collect the whole document into a `HashMap<element → Vec<HashMap<attr → value_str>>>`.
351    pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
352        let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
353        while let Some(ev) = self.next_event()? {
354            if let Event::StartTag { name, attributes } = ev {
355                let entry = map.entry(name.into()).or_default();
356                let mut attrs = HashMap::new();
357                for attr in attributes {
358                    attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
359                }
360                entry.push(attrs);
361            }
362        }
363        Ok(map)
364    }
365}
366
367/// Heap-owning wrapper. Stores the raw bytes and hands out [`AbxParser`]
368/// borrows without lifetime gymnastics on the call-site.
369///
370/// ```rust,ignore
371/// let owned = AbxParserOwned::new(std::fs::read("foo.abx")?)?;
372/// let xml = owned.parser()?.to_xml()?;
373/// ```
374#[derive(Debug)]
375pub struct AbxParserOwned {
376    data: Vec<u8>,
377}
378
379impl AbxParserOwned {
380    /// Validate the magic header and store the bytes.
381    pub fn new(data: Vec<u8>) -> Result<Self> {
382        if data.len() < 4 {
383            return Err(AbxError::UnexpectedEof("magic header"));
384        }
385        let magic: [u8; 4] = data[..4].try_into().unwrap();
386        if magic != MAGIC {
387            return Err(AbxError::InvalidMagic {
388                expected: MAGIC,
389                actual: magic,
390            });
391        }
392        Ok(Self { data })
393    }
394
395    /// Create a fresh [`AbxParser`] borrowing from the stored bytes.
396    pub fn parser(&self) -> Result<AbxParser<'_>> {
397        AbxParser::new(&self.data)
398    }
399}