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