use std::fs::File;
use std::io::{BufRead, BufReader};
use std::ops::Deref;
use std::path::Path;
use crate::errors::{Result, WellFormedError};
use crate::events::{BytesStart, BytesText, Event};
use crate::name::{
LocalName, Namespace, NamespaceBindingsIter, NamespaceError, NamespaceResolver, QName,
ResolveResult,
};
use crate::reader::{Config, Reader, Span, XmlSource};
#[derive(Debug, Clone)]
pub struct NsReader<R> {
pub(super) reader: Reader<R>,
ns_resolver: NamespaceResolver,
pending_pop: bool,
}
impl<R> NsReader<R> {
#[inline]
pub fn from_reader(reader: R) -> Self {
Self::new(Reader::from_reader(reader))
}
#[inline]
pub const fn config(&self) -> &Config {
self.reader.config()
}
#[inline]
pub fn config_mut(&mut self) -> &mut Config {
self.reader.config_mut()
}
}
impl<R> NsReader<R> {
#[inline]
fn new(mut reader: Reader<R>) -> Self {
reader.enable_namespace_constraints();
Self {
reader,
ns_resolver: NamespaceResolver::default(),
pending_pop: false,
}
}
fn read_event_impl<'i, B>(&mut self, buf: B) -> Result<Event<'i>>
where
R: XmlSource<'i, B>,
{
self.pop();
let event = self.reader.read_event_impl(buf);
self.process_event(event)
}
pub(super) fn pop(&mut self) {
if self.pending_pop {
self.ns_resolver.pop();
self.pending_pop = false;
}
}
pub(super) fn process_event<'i>(&mut self, event: Result<Event<'i>>) -> Result<Event<'i>> {
match event {
Ok(Event::Start(e)) => {
self.check_element_depth()?;
self.ns_resolver.push(&e)?;
self.check_namespace_constraints(&e)?;
Ok(Event::Start(e))
}
Ok(Event::Empty(e)) => {
self.check_element_depth()?;
self.ns_resolver.push(&e)?;
self.check_namespace_constraints(&e)?;
self.pending_pop = true;
Ok(Event::Empty(e))
}
Ok(Event::End(e)) => {
self.pending_pop = true;
Ok(Event::End(e))
}
e => e,
}
}
fn check_element_depth(&self) -> Result<()> {
let max = self.reader.config().max_element_depth;
if self.ns_resolver.level() >= max {
return Err(NamespaceError::TooDeeplyNested(max).into());
}
Ok(())
}
fn normalize_namespace(&self, uri: &[u8]) -> Vec<u8> {
let Ok(text) = std::str::from_utf8(uri) else {
return uri.to_vec();
};
match crate::escape::unescape_with(text, |name| self.reader.declared_entity(name)) {
Ok(unescaped) => unescaped.into_owned().into_bytes(),
Err(_) => uri.to_vec(),
}
}
fn check_namespace_constraints(&self, start: &BytesStart<'_>) -> Result<()> {
if !self.reader.config().check_well_formedness {
return Ok(());
}
if let ResolveResult::Unknown(prefix) = self.ns_resolver.resolve_element(start.name()).0 {
return Err(NamespaceError::UnknownPrefix(prefix).into());
}
let mut seen: Vec<(Option<Vec<u8>>, Vec<u8>)> = Vec::new();
for attribute in start.attributes() {
let attribute = attribute?;
let key = attribute.key;
if key.as_ref() == b"xmlns" || key.as_ref().starts_with(b"xmlns:") {
continue;
}
let (namespace, local) = self.ns_resolver.resolve_attribute(key);
let namespace = match namespace {
ResolveResult::Unknown(prefix) => {
return Err(NamespaceError::UnknownPrefix(prefix).into());
}
ResolveResult::Bound(Namespace(uri)) => Some(self.normalize_namespace(uri)),
ResolveResult::Unbound => None,
};
let expanded = (namespace, local.as_ref().to_vec());
if seen.contains(&expanded) {
let name = String::from_utf8_lossy(key.as_ref()).into_owned();
return Err(WellFormedError::DuplicateAttribute(name).into());
}
seen.push(expanded);
}
Ok(())
}
}
impl<R> NsReader<R> {
#[inline]
pub fn into_inner(self) -> R {
self.reader.into_inner()
}
#[inline]
pub const fn get_ref(&self) -> &R {
self.reader.get_ref()
}
#[inline]
pub fn get_mut(&mut self) -> &mut R {
self.reader.get_mut()
}
#[inline]
pub const fn resolver(&self) -> &NamespaceResolver {
&self.ns_resolver
}
#[inline]
pub fn resolver_mut(&mut self) -> &mut NamespaceResolver {
&mut self.ns_resolver
}
#[inline]
pub fn resolve<'n>(
&self,
name: QName<'n>,
attribute: bool,
) -> (ResolveResult<'_>, LocalName<'n>) {
self.ns_resolver.resolve(name, !attribute)
}
#[inline]
pub fn resolve_element<'n>(&self, name: QName<'n>) -> (ResolveResult<'_>, LocalName<'n>) {
self.ns_resolver.resolve_element(name)
}
#[inline]
pub fn resolve_attribute<'n>(&self, name: QName<'n>) -> (ResolveResult<'_>, LocalName<'n>) {
self.ns_resolver.resolve_attribute(name)
}
#[inline]
pub fn prefixes(&self) -> NamespaceBindingsIter<'_> {
self.ns_resolver.bindings()
}
}
impl<R: BufRead> NsReader<R> {
#[inline]
pub fn read_event_into<'b>(&mut self, buf: &'b mut Vec<u8>) -> Result<Event<'b>> {
self.read_event_impl(buf)
}
#[inline]
pub fn read_resolved_event_into<'b>(
&mut self,
buf: &'b mut Vec<u8>,
) -> Result<(ResolveResult<'_>, Event<'b>)> {
let event = self.read_event_impl(buf)?;
Ok(self.ns_resolver.resolve_event(event))
}
#[inline]
pub fn read_to_end_into(&mut self, end: QName, buf: &mut Vec<u8>) -> Result<Span> {
let result = self.reader.read_to_end_into(end, buf)?;
self.ns_resolver.pop();
Ok(result)
}
#[inline]
pub fn read_text_into<'b>(
&mut self,
end: QName,
buf: &'b mut Vec<u8>,
) -> Result<BytesText<'b>> {
let result = self.reader.read_text_into(end, buf)?;
self.ns_resolver.pop();
Ok(result)
}
}
impl NsReader<BufReader<File>> {
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(Self::new(Reader::from_file(path)?))
}
}
impl<'i> NsReader<&'i [u8]> {
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &'i str) -> Self {
Self::new(Reader::from_str(s))
}
#[inline]
pub fn read_event(&mut self) -> Result<Event<'i>> {
self.read_event_impl(())
}
#[inline]
pub fn read_resolved_event(&mut self) -> Result<(ResolveResult<'_>, Event<'i>)> {
let event = self.read_event_impl(())?;
Ok(self.ns_resolver.resolve_event(event))
}
#[inline]
pub fn read_to_end(&mut self, end: QName) -> Result<Span> {
let result = self.reader.read_to_end(end)?;
self.ns_resolver.pop();
Ok(result)
}
#[inline]
pub fn read_text(&mut self, end: QName) -> Result<BytesText<'i>> {
let result = self.reader.read_text(end)?;
self.ns_resolver.pop();
Ok(result)
}
}
impl<R> Deref for NsReader<R> {
type Target = Reader<R>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.reader
}
}
#[cfg(test)]
mod tests;