Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
211 lines
5.3 KiB
Rust
211 lines
5.3 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use std::{
|
|
borrow::Cow,
|
|
fmt::{Display, Formatter},
|
|
};
|
|
|
|
use quick_xml::events::BytesStart;
|
|
use tokenizer::Tokenizer;
|
|
|
|
use crate::schema::{Element, NamedElement, Namespace};
|
|
|
|
pub mod header;
|
|
pub mod property;
|
|
pub mod tokenizer;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Error {
|
|
Xml(Box<quick_xml::Error>),
|
|
UnexpectedToken(Box<UnexpectedToken>),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct UnexpectedToken {
|
|
pub expected: Option<Token<'static>>,
|
|
pub found: Token<'static>,
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Token<'x> {
|
|
ElementStart {
|
|
name: NamedElement,
|
|
raw: RawElement<'x>,
|
|
},
|
|
ElementEnd,
|
|
Bytes(Cow<'x, [u8]>),
|
|
Text(Cow<'x, str>),
|
|
UnknownElement(RawElement<'x>),
|
|
Eof,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct RawElement<'x> {
|
|
pub element: BytesStart<'x>,
|
|
pub namespace: Option<Cow<'static, [u8]>>,
|
|
}
|
|
|
|
pub trait DavParser: Sized {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> Result<Self>;
|
|
}
|
|
|
|
pub trait XmlValueParser: Sized {
|
|
fn parse_bytes(bytes: &[u8]) -> Option<Self>;
|
|
fn parse_str(text: &str) -> Option<Self>;
|
|
}
|
|
|
|
impl NamedElement {
|
|
pub fn dav(element: Element) -> NamedElement {
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element,
|
|
}
|
|
}
|
|
|
|
pub fn caldav(element: Element) -> NamedElement {
|
|
NamedElement {
|
|
ns: Namespace::CalDav,
|
|
element,
|
|
}
|
|
}
|
|
|
|
pub fn carddav(element: Element) -> NamedElement {
|
|
NamedElement {
|
|
ns: Namespace::CardDav,
|
|
element,
|
|
}
|
|
}
|
|
|
|
pub fn calendarserver(element: Element) -> NamedElement {
|
|
NamedElement {
|
|
ns: Namespace::CalendarServer,
|
|
element,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Token<'_> {
|
|
pub fn into_owned(self) -> Token<'static> {
|
|
match self {
|
|
Token::ElementStart { name, raw } => Token::ElementStart {
|
|
name,
|
|
raw: raw.into_owned(),
|
|
},
|
|
Token::ElementEnd => Token::ElementEnd,
|
|
Token::Bytes(bytes) => Token::Bytes(bytes.into_owned().into()),
|
|
Token::Text(text) => Token::Text(text.into_owned().into()),
|
|
Token::UnknownElement(raw) => Token::UnknownElement(raw.into_owned()),
|
|
Token::Eof => Token::Eof,
|
|
}
|
|
}
|
|
|
|
pub fn into_unexpected(self) -> Error {
|
|
Error::UnexpectedToken(Box::new(UnexpectedToken {
|
|
expected: None,
|
|
found: self.into_owned(),
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl<'x> RawElement<'x> {
|
|
pub fn new(element: BytesStart<'x>) -> Self {
|
|
RawElement {
|
|
element,
|
|
namespace: None,
|
|
}
|
|
}
|
|
|
|
pub fn with_namespace(self, namespace: quick_xml::name::Namespace<'_>) -> Self {
|
|
RawElement {
|
|
element: self.element,
|
|
namespace: Some(Cow::Owned(namespace.into_inner().to_vec())),
|
|
}
|
|
}
|
|
|
|
pub fn with_namespace_static(self, namespace: &'static [u8]) -> Self {
|
|
RawElement {
|
|
element: self.element,
|
|
namespace: Some(Cow::Borrowed(namespace)),
|
|
}
|
|
}
|
|
|
|
pub fn into_owned(self) -> RawElement<'static> {
|
|
RawElement {
|
|
element: self.element.into_owned(),
|
|
namespace: self.namespace,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
impl PartialEq for Token<'_> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(
|
|
Self::ElementStart {
|
|
name: l_name,
|
|
raw: l_raw,
|
|
},
|
|
Self::ElementStart {
|
|
name: r_name,
|
|
raw: r_raw,
|
|
},
|
|
) => {
|
|
l_name == r_name
|
|
&& l_raw
|
|
.element
|
|
.attributes_raw()
|
|
.trim_ascii()
|
|
.eq_ignore_ascii_case(r_raw.element.attributes_raw().trim_ascii())
|
|
}
|
|
(Self::Bytes(l0), Self::Bytes(r0)) => l0 == r0,
|
|
(Self::Text(l0), Self::Text(r0)) => l0 == r0,
|
|
(Self::UnknownElement(l0), Self::UnknownElement(r0)) => {
|
|
let l0: &[u8] = l0.element.as_ref();
|
|
let r0: &[u8] = r0.element.as_ref();
|
|
l0.eq_ignore_ascii_case(r0)
|
|
}
|
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl NamedElement {
|
|
pub fn into_unexpected(self) -> Error {
|
|
Error::UnexpectedToken(Box::new(UnexpectedToken {
|
|
expected: None,
|
|
found: Token::ElementStart {
|
|
name: self,
|
|
raw: RawElement::new(BytesStart::new("")),
|
|
},
|
|
}))
|
|
}
|
|
}
|
|
|
|
impl Default for RawElement<'_> {
|
|
fn default() -> Self {
|
|
RawElement::new(BytesStart::new(""))
|
|
}
|
|
}
|
|
|
|
impl Display for Error {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Error::Xml(err) => write!(f, "XML error: {}", err),
|
|
Error::UnexpectedToken(err) => {
|
|
write!(f, "Unexpected token: {:?}", err.found)?;
|
|
if let Some(expected) = &err.expected {
|
|
write!(f, ", expected: {expected:?}")?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|