diff --git a/Cargo.lock b/Cargo.lock index 2a1e2b4..01b65b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2599,9 +2599,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.5" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 4e163f2..8319204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ tokio = { version = "1", features = [ url = "2.5" base64 = "0.22" thiserror = "2.0" -quick-xml = { version = "0.37" } +quick-xml = { version = "0.38" } rust-embed = "8.5" tower-sessions = "0.14" futures-core = "0.3.31" diff --git a/crates/dav/src/xml/propfind.rs b/crates/dav/src/xml/propfind.rs index dbee279..8962268 100644 --- a/crates/dav/src/xml/propfind.rs +++ b/crates/dav/src/xml/propfind.rs @@ -66,6 +66,9 @@ impl XmlDeserialize for PropElement { Event::Text(_) | Event::CData(_) => { return Err(XmlError::UnsupportedEvent("Not expecting text here")); } + Event::GeneralRef(_) => { + return Err(::rustical_xml::XmlError::UnsupportedEvent("GeneralRef")); + } Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { /* ignore */ } Event::End(_end) => { diff --git a/crates/dav/src/xml/tag_list.rs b/crates/dav/src/xml/tag_list.rs index bf7b126..506d22d 100644 --- a/crates/dav/src/xml/tag_list.rs +++ b/crates/dav/src/xml/tag_list.rs @@ -29,12 +29,9 @@ impl XmlSerialize for TagList { }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname - .as_ref() - .map(|tagname| ::quick_xml::name::QName(tagname.as_bytes())); - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); + if let Some(tagname) = tagname.as_ref() { + let mut bytes_start = BytesStart::new(tagname); if !has_prefix && let Some(ns) = &ns { bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); } @@ -49,8 +46,8 @@ impl XmlSerialize for TagList { el.write_empty()?; } - if let Some(qname) = &qname { - writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; + if let Some(tagname) = tagname.as_ref() { + writer.write_event(Event::End(BytesEnd::new(tagname)))?; } Ok(()) } diff --git a/crates/xml/derive/src/xml_enum/impl_se.rs b/crates/xml/derive/src/xml_enum/impl_se.rs index f45d204..0ac9f21 100644 --- a/crates/xml/derive/src/xml_enum/impl_se.rs +++ b/crates/xml/derive/src/xml_enum/impl_se.rs @@ -34,12 +34,11 @@ impl Enum { }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname.as_ref().map(|tagname| ::quick_xml::name::QName(tagname.as_bytes())); const enum_untagged: bool = #enum_untagged; - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); + if let Some(tagname) = tagname.as_ref() { + let mut bytes_start = BytesStart::new(tagname); if !has_prefix { if let Some(ns) = &ns { bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); @@ -50,8 +49,8 @@ impl Enum { #(#variant_serializers);* - if let Some(qname) = &qname { - writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; + if let Some(tagname) = tagname.as_ref() { + writer.write_event(Event::End(BytesEnd::new(tagname)))?; } Ok(()) } diff --git a/crates/xml/derive/src/xml_enum/mod.rs b/crates/xml/derive/src/xml_enum/mod.rs index d444649..027e7be 100644 --- a/crates/xml/derive/src/xml_enum/mod.rs +++ b/crates/xml/derive/src/xml_enum/mod.rs @@ -66,6 +66,9 @@ impl Enum { Event::CData(cdata) => { return Err(::rustical_xml::XmlError::UnsupportedEvent("CDATA")); } + Event::GeneralRef(_) => { + return Err(::rustical_xml::XmlError::UnsupportedEvent("GeneralRef")); + } Event::Decl(_) => { /* ignore this */ } Event::Comment(_) => { /* ignore */ } Event::DocType(_) => { /* ignore */ } diff --git a/crates/xml/derive/src/xml_struct/impl_se.rs b/crates/xml/derive/src/xml_struct/impl_se.rs index 07e019b..d7431c6 100644 --- a/crates/xml/derive/src/xml_struct/impl_se.rs +++ b/crates/xml/derive/src/xml_struct/impl_se.rs @@ -111,10 +111,9 @@ impl NamedStruct { }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname.as_ref().map(|tagname| ::quick_xml::name::QName(tagname.as_bytes())); - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); + if let Some(tagname) = tagname.as_ref() { + let mut bytes_start = BytesStart::new(tagname); if !has_prefix { if let Some(ns) = &ns { bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); @@ -133,8 +132,8 @@ impl NamedStruct { } if !#is_empty { #(#tag_writers);* - if let Some(qname) = &qname { - writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; + if let Some(tagname) = tagname.as_ref() { + writer.write_event(Event::End(BytesEnd::new(tagname)))?; } } Ok(()) diff --git a/crates/xml/derive/src/xml_struct/mod.rs b/crates/xml/derive/src/xml_struct/mod.rs index d79ae4f..dc5a49b 100644 --- a/crates/xml/derive/src/xml_struct/mod.rs +++ b/crates/xml/derive/src/xml_struct/mod.rs @@ -148,6 +148,8 @@ impl NamedStruct { } } + let mut string = String::new(); + if !empty { loop { let event = reader.read_event_into(&mut buf)?; @@ -167,12 +169,23 @@ impl NamedStruct { } } Event::Text(bytes_text) => { - let text = bytes_text.unescape()?; - #(#text_field_branches)* + let text = bytes_text.decode()?; + string.push_str(&text); } Event::CData(cdata) => { let text = String::from_utf8(cdata.to_vec())?; - #(#text_field_branches)* + string.push_str(&text); + } + Event::GeneralRef(gref) => { + if let Some(char) = gref.resolve_char_ref()? { + string.push(char); + } else if let Some(text) = + quick_xml::escape::resolve_xml_entity(&gref.xml_content()?) + { + string.push_str(text); + } else { + return Err(XmlError::UnsupportedEvent("invalid XML ref")); + } } Event::Decl(_) => { /* ignore this */ } Event::Comment(_) => { /* ignore */ } @@ -185,6 +198,9 @@ impl NamedStruct { } } + let text = string; + #(#text_field_branches)* + Ok(Self { #(#builder_field_builds),* }) diff --git a/crates/xml/src/error.rs b/crates/xml/src/error.rs index 5812733..77bc5f5 100644 --- a/crates/xml/src/error.rs +++ b/crates/xml/src/error.rs @@ -8,6 +8,8 @@ pub enum XmlError { #[error(transparent)] QuickXmlError(#[from] quick_xml::Error), #[error(transparent)] + QuickXmlEncodingError(#[from] quick_xml::encoding::EncodingError), + #[error(transparent)] QuickXmlAttrError(#[from] quick_xml::events::attributes::AttrError), #[error(transparent)] FromUtf8Error(#[from] FromUtf8Error), diff --git a/crates/xml/src/se.rs b/crates/xml/src/se.rs index 4d0365c..7ef9fff 100644 --- a/crates/xml/src/se.rs +++ b/crates/xml/src/se.rs @@ -1,7 +1,7 @@ use crate::XmlRootTag; use quick_xml::{ events::{BytesStart, Event, attributes::Attribute}, - name::{Namespace, QName}, + name::Namespace, }; use std::collections::HashMap; pub use xml_derive::XmlSerialize; @@ -76,9 +76,8 @@ impl XmlSerialize for () { }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname.as_ref().map(|tagname| QName(tagname.as_bytes())); - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); + if let Some(tagname) = tagname.as_ref() { + let mut bytes_start = BytesStart::new(tagname); if !has_prefix && let Some(ns) = &ns { bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); } diff --git a/crates/xml/src/value.rs b/crates/xml/src/value.rs index 2735f60..cfc9b9a 100644 --- a/crates/xml/src/value.rs +++ b/crates/xml/src/value.rs @@ -1,6 +1,6 @@ use crate::{XmlDeserialize, XmlError, XmlSerialize}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; -use quick_xml::name::{Namespace, QName}; +use quick_xml::name::Namespace; use std::collections::HashMap; use std::num::{ParseFloatError, ParseIntError}; use std::{convert::Infallible, io::BufRead}; @@ -77,20 +77,23 @@ impl XmlDeserialize for T { loop { match reader.read_event_into(&mut buf)? { Event::Text(bytes_text) => { - let text = bytes_text.unescape()?; - if !string.is_empty() { - // Content already written - return Err(XmlError::UnsupportedEvent("content already written")); - } - string = text.to_string(); + let text = bytes_text.decode()?; + string.push_str(&text); } Event::CData(cdata) => { let text = String::from_utf8(cdata.to_vec())?; - if !string.is_empty() { - // Content already written - return Err(XmlError::UnsupportedEvent("content already written")); + string.push_str(&text); + } + Event::GeneralRef(gref) => { + if let Some(char) = gref.resolve_char_ref()? { + string.push(char); + } else if let Some(text) = + quick_xml::escape::resolve_xml_entity(&gref.xml_content()?) + { + string.push_str(text); + } else { + return Err(XmlError::UnsupportedEvent("invalid XML ref")); } - string = text; } Event::End(_) => break, Event::Eof => return Err(XmlError::Eof), @@ -123,17 +126,16 @@ impl XmlSerialize for T { }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname.as_ref().map(|tagname| QName(tagname.as_bytes())); - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); + if let Some(tagname) = tagname.as_ref() { + let mut bytes_start = BytesStart::new(tagname); if !has_prefix && let Some(ns) = &ns { bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); } writer.write_event(Event::Start(bytes_start))?; } writer.write_event(Event::Text(BytesText::new(&self.serialize())))?; - if let Some(qname) = &qname { - writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?; + if let Some(tagname) = tagname { + writer.write_event(Event::End(BytesEnd::new(tagname)))?; } Ok(()) } diff --git a/crates/xml/tests/de_struct.rs b/crates/xml/tests/de_struct.rs index 70c1450..307cfc7 100644 --- a/crates/xml/tests/de_struct.rs +++ b/crates/xml/tests/de_struct.rs @@ -275,7 +275,7 @@ fn test_xml_cdata() { - > + nice>text "#, ) @@ -285,11 +285,25 @@ fn test_xml_cdata() { Document { hello: "some text".to_owned(), href: "some stuff".to_owned(), - okay: ">".to_owned() + okay: "nice>text".to_owned() } ); } +#[test] +fn test_quickxml_bytesref() { + let gt = quick_xml::events::BytesRef::new("gt"); + assert!(!gt.is_char_ref()); + let result = if !gt.is_char_ref() { + quick_xml::escape::resolve_xml_entity(>.xml_content().unwrap()) + .unwrap() + .to_string() + } else { + gt.xml_content().unwrap().to_string() + }; + assert_eq!(result, ">"); +} + #[test] fn test_struct_xml_decl() { #[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)] @@ -307,14 +321,14 @@ fn test_struct_xml_decl() { let doc = Document::parse_str( r#" - Hello!"#, + Hello!&"#, ) .unwrap(); assert_eq!( doc, Document { child: Child { - text: "Hello!".to_owned() + text: "Hello!&".to_owned() } } );