use std::collections::HashMap;
use crate::{AbxError, Attribute, AttributeValue, Event, MAGIC, Result, render_event};
use super::grammar;
use crate::InternedStr;
pub(crate) fn check_magic(input: &[u8]) -> Result<()> {
let Some(&magic) = input.first_chunk::<4>() else {
return Err(AbxError::UnexpectedEof("magic header"));
};
if magic != MAGIC {
return Err(AbxError::InvalidMagic {
expected: MAGIC,
actual: magic,
});
}
Ok(())
}
#[derive(Debug)]
pub struct AbxParser<'a> {
rest: &'a [u8],
pool: Vec<InternedStr>,
}
impl<'a> AbxParser<'a> {
pub fn new(input: &'a [u8]) -> Result<Self> {
check_magic(input)?;
Ok(AbxParser {
rest: &input[4..],
pool: Vec::with_capacity(32),
})
}
pub fn is_empty(&self) -> bool {
self.rest.is_empty()
}
pub fn next_event(&mut self) -> Result<Option<Event>> {
if self.rest.is_empty() {
return Ok(None);
}
let mut input = self.rest;
let pool_len = self.pool.len();
match grammar::event(&mut input, &mut self.pool) {
Ok(ev) => {
self.rest = input;
Ok(Some(ev))
}
Err(e) => {
self.pool.truncate(pool_len);
Err(grammar::into_abx_error(e))
}
}
}
pub fn collect_events(&mut self) -> Result<Vec<Event>> {
let mut events = Vec::new();
while let Some(ev) = self.next_event()? {
events.push(ev);
}
Ok(events)
}
pub fn find_attribute(&mut self, element: &str, attr: &str) -> Result<Option<AttributeValue>> {
loop {
match self.next_event()? {
Some(Event::StartTag { name, attributes }) if name == element => {
if let Some(a) = attributes.into_iter().find(|a| a.name == attr) {
return Ok(Some(a.value));
}
}
Some(Event::EndDocument) | None => return Ok(None),
_ => {}
}
}
}
pub fn find_all_attributes(
&mut self,
element: &str,
attr: &str,
) -> Result<Vec<AttributeValue>> {
let mut out = Vec::new();
while let Some(ev) = self.next_event()? {
if let Event::StartTag { name, attributes } = ev
&& name == element
{
out.extend(
attributes
.into_iter()
.filter(|a| a.name == attr)
.map(|a| a.value),
);
}
}
Ok(out)
}
pub fn attributes_of(&mut self, element: &str) -> Result<Option<Vec<Attribute>>> {
loop {
match self.next_event()? {
Some(Event::StartTag { name, attributes }) if name == element => {
return Ok(Some(attributes));
}
Some(Event::EndDocument) | None => return Ok(None),
_ => {}
}
}
}
pub fn all_attributes_of(&mut self, element: &str) -> Result<Vec<Vec<Attribute>>> {
let mut out = Vec::new();
while let Some(ev) = self.next_event()? {
if let Event::StartTag { name, attributes } = ev
&& name == element
{
out.push(attributes);
}
}
Ok(out)
}
pub fn to_xml(&mut self) -> Result<String> {
let mut buf = String::from(r#"<?xml version="1.0" encoding="UTF-8"?>"#);
while let Some(ev) = self.next_event()? {
if matches!(ev, Event::EndDocument) {
break;
}
render_event(&ev, &mut buf);
}
Ok(buf)
}
pub fn write_xml(&mut self, writer: &mut impl std::io::Write) -> Result<()> {
writer.write_all(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
let mut tmp = String::new();
while let Some(ev) = self.next_event()? {
if matches!(ev, Event::EndDocument) {
break;
}
tmp.clear();
render_event(&ev, &mut tmp);
writer.write_all(tmp.as_bytes())?;
}
Ok(())
}
#[cfg(feature = "serde")]
pub fn deserialize_next<T: serde::de::DeserializeOwned>(
&mut self,
element: &str,
) -> Result<Option<T>> {
crate::de::find_and_consume_element(self, element)
}
#[cfg(feature = "serde")]
pub fn deserialize_all<T: serde::de::DeserializeOwned>(
&mut self,
element: &str,
) -> Result<Vec<T>> {
let mut out = Vec::new();
while let Some(item) = self.deserialize_next(element)? {
out.push(item);
}
Ok(out)
}
pub fn into_map(mut self) -> Result<HashMap<String, Vec<HashMap<String, String>>>> {
let mut map: HashMap<String, Vec<HashMap<String, String>>> = HashMap::new();
while let Some(ev) = self.next_event()? {
if let Event::StartTag { name, attributes } = ev {
let entry = map.entry(name.into()).or_default();
let mut attrs = HashMap::new();
for attr in attributes {
attrs.insert(attr.name.into(), attr.value.as_str().into_owned());
}
entry.push(attrs);
}
}
Ok(map)
}
}
#[derive(Debug)]
pub struct AbxParserOwned {
data: Vec<u8>,
}
impl AbxParserOwned {
pub fn new(data: Vec<u8>) -> Result<Self> {
check_magic(&data)?;
Ok(Self { data })
}
pub fn parser(&self) -> Result<AbxParser<'_>> {
AbxParser::new(&self.data)
}
}