use crate::errors::{Error, Result};
use crate::events::attributes::Attribute;
use crate::events::BytesStart;
use crate::utils::write_byte_string;
use memchr::memchr;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Formatter};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct QName<'a>(pub &'a [u8]);
impl<'a> QName<'a> {
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
self.0
}
pub fn local_name(&self) -> LocalName<'a> {
LocalName(self.index().map_or(self.0, |i| &self.0[i + 1..]))
}
pub fn prefix(&self) -> Option<Prefix<'a>> {
self.index().map(|i| Prefix(&self.0[..i]))
}
pub fn decompose(&self) -> (LocalName<'a>, Option<Prefix<'a>>) {
match self.index() {
None => (LocalName(self.0), None),
Some(i) => (LocalName(&self.0[i + 1..]), Some(Prefix(&self.0[..i]))),
}
}
pub fn as_namespace_binding(&self) -> Option<PrefixDeclaration<'a>> {
if self.0.starts_with(b"xmlns") {
return match self.0.get(5) {
None => Some(PrefixDeclaration::Default),
Some(&b':') => Some(PrefixDeclaration::Named(&self.0[6..])),
_ => None,
};
}
None
}
#[inline(always)]
fn index(&self) -> Option<usize> {
memchr(b':', self.0)
}
}
impl<'a> Debug for QName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "QName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for QName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct LocalName<'a>(&'a [u8]);
impl<'a> LocalName<'a> {
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for LocalName<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "LocalName(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for LocalName<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl<'a> From<QName<'a>> for LocalName<'a> {
#[inline]
fn from(name: QName<'a>) -> Self {
Self(name.index().map_or(name.0, |i| &name.0[i + 1..]))
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Prefix<'a>(&'a [u8]);
impl<'a> Prefix<'a> {
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for Prefix<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Prefix(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Prefix<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PrefixDeclaration<'a> {
Default,
Named(&'a [u8]),
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
pub struct Namespace<'a>(pub &'a [u8]);
impl<'a> Namespace<'a> {
#[inline(always)]
pub fn into_inner(self) -> &'a [u8] {
self.0
}
}
impl<'a> Debug for Namespace<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Namespace(")?;
write_byte_string(f, self.0)?;
write!(f, ")")
}
}
impl<'a> AsRef<[u8]> for Namespace<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ResolveResult<'ns> {
Unbound,
Bound(Namespace<'ns>),
Unknown(Vec<u8>),
}
impl<'ns> Debug for ResolveResult<'ns> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Unbound => write!(f, "Unbound"),
Self::Bound(ns) => write!(f, "Bound({:?})", ns),
Self::Unknown(p) => {
write!(f, "Unknown(")?;
write_byte_string(f, p)?;
write!(f, ")")
}
}
}
}
impl<'ns> TryFrom<ResolveResult<'ns>> for Option<Namespace<'ns>> {
type Error = Error;
fn try_from(result: ResolveResult<'ns>) -> Result<Self> {
use ResolveResult::*;
match result {
Unbound => Ok(None),
Bound(ns) => Ok(Some(ns)),
Unknown(p) => Err(Error::UnknownPrefix(p)),
}
}
}
#[derive(Debug, Clone)]
struct NamespaceEntry {
start: usize,
prefix_len: usize,
value_len: usize,
level: i32,
}
impl NamespaceEntry {
#[inline]
fn prefix<'b>(&self, ns_buffer: &'b [u8]) -> Option<Prefix<'b>> {
if self.prefix_len == 0 {
None
} else {
Some(Prefix(&ns_buffer[self.start..self.start + self.prefix_len]))
}
}
#[inline]
fn namespace<'ns>(&self, buffer: &'ns [u8]) -> ResolveResult<'ns> {
if self.value_len == 0 {
ResolveResult::Unbound
} else {
let start = self.start + self.prefix_len;
ResolveResult::Bound(Namespace(&buffer[start..start + self.value_len]))
}
}
}
#[derive(Debug, Default, Clone)]
pub(crate) struct NamespaceResolver {
bindings: Vec<NamespaceEntry>,
nesting_level: i32,
}
impl NamespaceResolver {
pub fn push(&mut self, start: &BytesStart, buffer: &mut Vec<u8>) {
self.nesting_level += 1;
let level = self.nesting_level;
for a in start.attributes().with_checks(false) {
if let Ok(Attribute { key: k, value: v }) = a {
match k.as_namespace_binding() {
Some(PrefixDeclaration::Default) => {
let start = buffer.len();
buffer.extend_from_slice(&v);
self.bindings.push(NamespaceEntry {
start,
prefix_len: 0,
value_len: v.len(),
level,
});
}
Some(PrefixDeclaration::Named(prefix)) => {
let start = buffer.len();
buffer.extend_from_slice(prefix);
buffer.extend_from_slice(&v);
self.bindings.push(NamespaceEntry {
start,
prefix_len: prefix.len(),
value_len: v.len(),
level,
});
}
None => {}
}
} else {
break;
}
}
}
pub fn pop(&mut self, buffer: &mut Vec<u8>) {
self.nesting_level -= 1;
let current_level = self.nesting_level;
match self.bindings.iter().rposition(|n| n.level <= current_level) {
None => {
buffer.clear();
self.bindings.clear();
}
Some(last_valid_pos) => {
if let Some(len) = self.bindings.get(last_valid_pos + 1).map(|n| n.start) {
buffer.truncate(len);
self.bindings.truncate(last_valid_pos + 1);
}
}
}
}
#[inline]
pub fn resolve<'n, 'ns>(
&self,
name: QName<'n>,
buffer: &'ns [u8],
use_default: bool,
) -> (ResolveResult<'ns>, LocalName<'n>) {
let (local_name, prefix) = name.decompose();
(self.resolve_prefix(prefix, buffer, use_default), local_name)
}
#[inline]
pub fn find<'ns>(&self, element_name: QName, buffer: &'ns [u8]) -> ResolveResult<'ns> {
self.resolve_prefix(element_name.prefix(), buffer, true)
}
fn resolve_prefix<'ns>(
&self,
prefix: Option<Prefix>,
buffer: &'ns [u8],
use_default: bool,
) -> ResolveResult<'ns> {
self.bindings
.iter()
.rev()
.find_map(|n| match (n.prefix(buffer), prefix) {
(None, None) if use_default => Some(n.namespace(buffer)),
(None, None) => Some(ResolveResult::Unbound),
(None, Some(_)) => None,
(Some(_), None) => None,
(Some(definition), Some(usage)) if definition != usage => None,
_ if n.value_len == 0 => Some(Self::maybe_unknown(prefix)),
_ => Some(n.namespace(buffer)),
})
.unwrap_or_else(|| Self::maybe_unknown(prefix))
}
#[inline]
fn maybe_unknown(prefix: Option<Prefix>) -> ResolveResult<'static> {
match prefix {
Some(p) => ResolveResult::Unknown(p.into_inner().to_vec()),
None => ResolveResult::Unbound,
}
}
}
#[cfg(test)]
mod namespaces {
use super::*;
use pretty_assertions::assert_eq;
use ResolveResult::*;
mod unprefixed {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"simple");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(
&BytesStart::from_content(" xmlns='default'", 0),
&mut buffer,
);
assert_eq!(buffer, b"default");
resolver.push(&BytesStart::from_content("", 0), &mut buffer);
assert_eq!(buffer, b"default");
resolver.pop(&mut buffer);
assert_eq!(buffer, b"default");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name, &buffer), Bound(ns));
}
#[test]
fn override_namespace() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer);
resolver.push(&BytesStart::from_content(" xmlns='new'", 0), &mut buffer);
assert_eq!(buffer, b"oldnew");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(new_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name, &buffer), Bound(new_ns));
resolver.pop(&mut buffer);
assert_eq!(buffer, b"old");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name, &buffer), Bound(old_ns));
}
#[test]
fn reset() {
let name = QName(b"simple");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer);
resolver.push(&BytesStart::from_content(" xmlns=''", 0), &mut buffer);
assert_eq!(buffer, b"old");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Unbound, LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name, &buffer), Unbound);
resolver.pop(&mut buffer);
assert_eq!(buffer, b"old");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(old_ns), LocalName(b"simple"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unbound, LocalName(b"simple"))
);
assert_eq!(resolver.find(name, &buffer), Bound(old_ns));
}
}
mod declared_prefix {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn basic() {
let name = QName(b"p:with-declared-prefix");
let ns = Namespace(b"default");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(
&BytesStart::from_content(" xmlns:p='default'", 0),
&mut buffer,
);
assert_eq!(buffer, b"pdefault");
resolver.push(&BytesStart::from_content("", 0), &mut buffer);
assert_eq!(buffer, b"pdefault");
resolver.pop(&mut buffer);
assert_eq!(buffer, b"pdefault");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Bound(ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name, &buffer), Bound(ns));
}
#[test]
fn override_namespace() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let new_ns = Namespace(b"new");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer);
resolver.push(&BytesStart::from_content(" xmlns:p='new'", 0), &mut buffer);
assert_eq!(buffer, b"poldpnew");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Bound(new_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name, &buffer), Bound(new_ns));
resolver.pop(&mut buffer);
assert_eq!(buffer, b"pold");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name, &buffer), Bound(old_ns));
}
#[test]
fn reset() {
let name = QName(b"p:with-declared-prefix");
let old_ns = Namespace(b"old");
let mut resolver = NamespaceResolver::default();
let mut buffer = Vec::new();
resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer);
resolver.push(&BytesStart::from_content(" xmlns:p=''", 0), &mut buffer);
assert_eq!(buffer, b"poldp");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unknown(b"p".to_vec()), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name, &buffer), Unknown(b"p".to_vec()));
resolver.pop(&mut buffer);
assert_eq!(buffer, b"pold");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Bound(old_ns), LocalName(b"with-declared-prefix"))
);
assert_eq!(resolver.find(name, &buffer), Bound(old_ns));
}
}
#[test]
fn undeclared_prefix() {
let name = QName(b"unknown:prefix");
let resolver = NamespaceResolver::default();
let buffer = Vec::new();
assert_eq!(buffer, b"");
assert_eq!(
resolver.resolve(name, &buffer, true),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
assert_eq!(
resolver.resolve(name, &buffer, false),
(Unknown(b"unknown".to_vec()), LocalName(b"prefix"))
);
assert_eq!(resolver.find(name, &buffer), Unknown(b"unknown".to_vec()));
}
#[test]
fn prefix_and_local_name() {
let name = QName(b"foo:bus");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus"));
assert_eq!(name.decompose(), (LocalName(b"bus"), Some(Prefix(b"foo"))));
let name = QName(b"foo:");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b""));
assert_eq!(name.decompose(), (LocalName(b""), Some(Prefix(b"foo"))));
let name = QName(b":foo");
assert_eq!(name.prefix(), Some(Prefix(b"")));
assert_eq!(name.local_name(), LocalName(b"foo"));
assert_eq!(name.decompose(), (LocalName(b"foo"), Some(Prefix(b""))));
let name = QName(b"foo:bus:baz");
assert_eq!(name.prefix(), Some(Prefix(b"foo")));
assert_eq!(name.local_name(), LocalName(b"bus:baz"));
assert_eq!(
name.decompose(),
(LocalName(b"bus:baz"), Some(Prefix(b"foo")))
);
}
}