Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/de/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::forward_to_deserialize_any;

use crate::de::key::QNameDeserializer;
use crate::de::SimpleTypeDeserializer;
use crate::de::{EntityResolver, PredefinedEntityResolver};
use crate::errors::serialize::DeError;
use crate::events::attributes::Attributes;
use crate::XmlVersion;
Expand All @@ -25,6 +26,7 @@ impl<'i> Attributes<'i> {
/// ```
/// # use pretty_assertions::assert_eq;
/// use quick_xml::events::BytesStart;
/// use quick_xml::de::PredefinedEntityResolver;
/// use quick_xml::XmlVersion;
/// use serde::Deserialize;
///
Expand Down Expand Up @@ -71,13 +73,14 @@ impl<'i> Attributes<'i> {
self,
version: XmlVersion,
prefix: &'static str,
) -> AttributesDeserializer<'i> {
) -> AttributesDeserializer<'i, PredefinedEntityResolver> {
AttributesDeserializer {
iter: self,
value: None,
prefix,
key_buf: String::new(),
version,
resolver: &PredefinedEntityResolver,
}
}
}
Expand All @@ -96,7 +99,7 @@ impl<'i> Attributes<'i> {
/// In particular, when reader was created from a string, this is lifetime of the
/// string.
#[derive(Debug, Clone)]
pub struct AttributesDeserializer<'i> {
pub struct AttributesDeserializer<'i, E: EntityResolver = PredefinedEntityResolver> {
iter: Attributes<'i>,
/// The value of the attribute, read in last call to `next_key_seed`.
value: Option<Cow<'i, [u8]>>,
Expand All @@ -106,9 +109,36 @@ pub struct AttributesDeserializer<'i> {
/// Kept in the deserializer to avoid many small allocations
key_buf: String,
version: XmlVersion,
resolver: &'i E,
}

impl<'de> Deserializer<'de> for AttributesDeserializer<'de> {
impl<'i, OldE: EntityResolver> AttributesDeserializer<'i, OldE> {
/// Produce a copy of this deserializer with its
/// [`EntityResolver`] replaced by the one given.
pub fn with_resolver<NewE: EntityResolver>(
self,
resolver: &'i NewE,
) -> AttributesDeserializer<'i, NewE> {
let AttributesDeserializer {
iter,
value,
prefix,
key_buf,
version,
resolver: _,
} = self;
AttributesDeserializer {
iter,
value,
prefix,
key_buf,
version,
resolver,
}
}
}

impl<'de, E: EntityResolver> Deserializer<'de> for AttributesDeserializer<'de, E> {
type Error = DeError;

#[inline]
Expand All @@ -126,7 +156,7 @@ impl<'de> Deserializer<'de> for AttributesDeserializer<'de> {
}
}

impl<'de> MapAccess<'de> for AttributesDeserializer<'de> {
impl<'de, E: EntityResolver> MapAccess<'de> for AttributesDeserializer<'de, E> {
type Error = DeError;

fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
Expand Down Expand Up @@ -160,6 +190,7 @@ impl<'de> MapAccess<'de> for AttributesDeserializer<'de> {
0..value.len(),
self.version,
self.iter.decoder(),
self.resolver.clone(),
);
seed.deserialize(de)
}
Expand Down
2 changes: 2 additions & 0 deletions src/de/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ where
value,
self.de.reader.reader.xml_version(),
self.start.decoder(),
self.de.reader.entity_resolver.clone(),
)),
// This arm processes the following XML shape:
// <any-tag>
Expand Down Expand Up @@ -951,6 +952,7 @@ where
{
type Error = DeError;

#[cfg_attr(not(feature = "overlapped-lists"), allow(clippy::never_loop))]
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeError>
where
T: DeserializeSeed<'de>,
Expand Down
34 changes: 17 additions & 17 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@
//! [`impl_deserialize_for_internally_tagged_enum!`]: crate::impl_deserialize_for_internally_tagged_enum

macro_rules! forward_to_simple_type {
($deserialize:ident, $($mut:tt)?) => {
($deserialize:ident $(, $mut:tt)?) => {
#[inline]
fn $deserialize<V>($($mut)? self, visitor: V) -> Result<V::Value, DeError>
where
Expand All @@ -1989,27 +1989,27 @@ macro_rules! forward_to_simple_type {
/// byte arrays, booleans and identifiers.
macro_rules! deserialize_primitives {
($($mut:tt)?) => {
forward_to_simple_type!(deserialize_i8, $($mut)?);
forward_to_simple_type!(deserialize_i16, $($mut)?);
forward_to_simple_type!(deserialize_i32, $($mut)?);
forward_to_simple_type!(deserialize_i64, $($mut)?);
forward_to_simple_type!(deserialize_i8 $(, $mut)?);
forward_to_simple_type!(deserialize_i16 $(, $mut)?);
forward_to_simple_type!(deserialize_i32 $(, $mut)?);
forward_to_simple_type!(deserialize_i64 $(, $mut)?);

forward_to_simple_type!(deserialize_u8, $($mut)?);
forward_to_simple_type!(deserialize_u16, $($mut)?);
forward_to_simple_type!(deserialize_u32, $($mut)?);
forward_to_simple_type!(deserialize_u64, $($mut)?);
forward_to_simple_type!(deserialize_u8 $(, $mut)?);
forward_to_simple_type!(deserialize_u16 $(, $mut)?);
forward_to_simple_type!(deserialize_u32 $(, $mut)?);
forward_to_simple_type!(deserialize_u64 $(, $mut)?);

forward_to_simple_type!(deserialize_i128, $($mut)?);
forward_to_simple_type!(deserialize_u128, $($mut)?);
forward_to_simple_type!(deserialize_i128 $(, $mut)?);
forward_to_simple_type!(deserialize_u128 $(, $mut)?);

forward_to_simple_type!(deserialize_f32, $($mut)?);
forward_to_simple_type!(deserialize_f64, $($mut)?);
forward_to_simple_type!(deserialize_f32 $(, $mut)?);
forward_to_simple_type!(deserialize_f64 $(, $mut)?);

forward_to_simple_type!(deserialize_bool, $($mut)?);
forward_to_simple_type!(deserialize_char, $($mut)?);
forward_to_simple_type!(deserialize_bool $(, $mut)?);
forward_to_simple_type!(deserialize_char $(, $mut)?);

forward_to_simple_type!(deserialize_str, $($mut)?);
forward_to_simple_type!(deserialize_string, $($mut)?);
forward_to_simple_type!(deserialize_str $(, $mut)?);
forward_to_simple_type!(deserialize_string $(, $mut)?);

/// Forwards deserialization to the [`deserialize_any`](#method.deserialize_any).
#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/de/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use crate::events::BytesText;
///
/// assert_eq!(data.get("entity_one"), Some(&"entity 1".to_string()));
/// ```
pub trait EntityResolver {
pub trait EntityResolver: Clone {
/// The error type that represents DTD parse error
type Error: Error;

Expand Down
44 changes: 33 additions & 11 deletions src/de/simple_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
//! [as defined]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition

use crate::de::Text;
use crate::de::{EntityResolver, PredefinedEntityResolver};
use crate::encoding::Decoder;
use crate::errors::serialize::DeError;
use crate::escape::resolve_predefined_entity;
use crate::utils::{trim_xml_spaces, CowRef};
use crate::XmlVersion;
use memchr::memchr;
Expand Down Expand Up @@ -495,7 +495,7 @@ impl<'de, 'a> SeqAccess<'de> for ListIter<'de, 'a> {
/// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
/// [`FromStr`]: std::str::FromStr
/// [specification]: https://www.w3.org/TR/xmlschema11-2/#boolean
pub struct SimpleTypeDeserializer<'de, 'a> {
pub struct SimpleTypeDeserializer<'de, 'a, E: EntityResolver = PredefinedEntityResolver> {
/// - In case of attribute contains escaped attribute value
/// - In case of text contains unescaped text value
content: CowRef<'de, 'a, [u8]>,
Expand All @@ -505,9 +505,15 @@ pub struct SimpleTypeDeserializer<'de, 'a> {
/// Not used for deserializing raw byte buffers
decoder: Decoder,
version: XmlVersion,

/// Used to resolve unknown entities that would otherwise cause the parser
/// to return an [`EscapeError::UnrecognizedEntity`] error.
///
/// [`EscapeError::UnrecognizedEntity`]: crate::escape::EscapeError::UnrecognizedEntity
entity_resolver: E,
}

impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
impl<'de, 'a> SimpleTypeDeserializer<'de, 'a, PredefinedEntityResolver> {
/// Creates a deserializer from a value, that possible borrowed from input.
///
/// It is assumed that `text` does not have entities.
Expand All @@ -516,7 +522,13 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
Cow::Borrowed(slice) => CowRef::Input(slice.as_bytes()),
Cow::Owned(content) => CowRef::Owned(content.into_bytes()),
};
Self::new(content, false, XmlVersion::V1_0, Decoder::utf8())
Self::new(
content,
false,
XmlVersion::V1_0,
Decoder::utf8(),
PredefinedEntityResolver,
)
}
/// Creates a deserializer from an XML text node, that possible borrowed from input.
///
Expand All @@ -526,7 +538,9 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
pub fn from_text_content(value: Text<'de>) -> Self {
Self::from_text(value.text)
}
}

impl<'de, 'a, E: EntityResolver> SimpleTypeDeserializer<'de, 'a, E> {
/// Creates a deserializer from a part of value at specified range.
///
/// This constructor used internally to deserialize from attribute values.
Expand All @@ -536,12 +550,13 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
range: Range<usize>,
version: XmlVersion,
decoder: Decoder,
entity_resolver: E,
) -> Self {
let content = match value {
Cow::Borrowed(slice) => CowRef::Input(&slice[range]),
Cow::Owned(slice) => CowRef::Slice(&slice[range]),
};
Self::new(content, true, version, decoder)
Self::new(content, true, version, decoder, entity_resolver)
}

/// Constructor for tests
Expand All @@ -551,12 +566,14 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
is_attr: bool,
version: XmlVersion,
decoder: Decoder,
entity_resolver: E,
) -> Self {
Self {
content,
is_attr,
decoder,
version,
entity_resolver,
}
}

Expand All @@ -583,9 +600,9 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
fn content<'b>(&'b self) -> Result<CowRef<'de, 'b, str>, DeError> {
let content = self.decode()?;
if self.is_attr {
let value =
self.version
.normalize_attribute_value(&content, 128, resolve_predefined_entity)?;
let value = self
.version
.normalize_attribute_value(&content, 128, |x| self.entity_resolver.resolve(x))?;
return Ok(match value {
Cow::Borrowed(_) => content,
Cow::Owned(value) => CowRef::Owned(value),
Expand All @@ -595,7 +612,7 @@ impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
}
}

impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
impl<'de, 'a, E: EntityResolver> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a, E> {
type Error = DeError;

/// Forwards deserialization to the [`Self::deserialize_str`]
Expand Down Expand Up @@ -739,7 +756,7 @@ impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
}
}

impl<'de, 'a> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a> {
impl<'de, 'a, E: EntityResolver> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a, E> {
type Error = DeError;
type Variant = UnitOnly;

Expand All @@ -752,7 +769,9 @@ impl<'de, 'a> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a> {
}
}

impl<'de, 'a> IntoDeserializer<'de, DeError> for SimpleTypeDeserializer<'de, 'a> {
impl<'de, 'a, E: EntityResolver> IntoDeserializer<'de, DeError>
for SimpleTypeDeserializer<'de, 'a, E>
{
type Deserializer = Self;

#[inline]
Expand Down Expand Up @@ -784,6 +803,7 @@ mod tests {
true,
XmlVersion::V1_0,
decoder,
PredefinedEntityResolver,
);
let data: $type = Deserialize::deserialize(de).unwrap();

Expand All @@ -803,6 +823,7 @@ mod tests {
true,
XmlVersion::V1_0,
decoder,
PredefinedEntityResolver,
);
let data: $type = Deserialize::deserialize(de).unwrap();

Expand Down Expand Up @@ -833,6 +854,7 @@ mod tests {
true,
XmlVersion::V1_0,
decoder,
PredefinedEntityResolver,
);
let err = <$type as Deserialize>::deserialize(de).unwrap_err();

Expand Down
1 change: 1 addition & 0 deletions src/de/text.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
de::simple_type::SimpleTypeDeserializer,
de::PredefinedEntityResolver,
de::{Text, TEXT_KEY},
errors::serialize::DeError,
};
Expand Down
Loading