mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-28 04:06:54 -06:00
Generated
+4
-13
@@ -994,7 +994,7 @@ dependencies = [
|
||||
"hayro-syntax",
|
||||
"kurbo",
|
||||
"log",
|
||||
"quick-xml 0.38.4",
|
||||
"quick-xml",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1058,7 +1058,7 @@ dependencies = [
|
||||
"designcraft-compose",
|
||||
"designcraft-doc",
|
||||
"designcraft-geom",
|
||||
"quick-xml 0.38.4",
|
||||
"quick-xml",
|
||||
"thiserror 2.0.21",
|
||||
"zip",
|
||||
]
|
||||
@@ -1132,7 +1132,7 @@ name = "designcraft-textimport"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"designcraft-doc",
|
||||
"quick-xml 0.38.4",
|
||||
"quick-xml",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -3514,15 +3514,6 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
@@ -5009,7 +5000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml 0.41.0",
|
||||
"quick-xml",
|
||||
"quote",
|
||||
]
|
||||
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ flo_curves = "0.8"
|
||||
# QR codes (Object › Generate QR Code); MIT.
|
||||
qrcodegen = "1.8"
|
||||
hayro = "0.7"
|
||||
quick-xml = "0.38"
|
||||
quick-xml = "0.41"
|
||||
zip = { version = "3", default-features = false, features = ["deflate"] }
|
||||
|
||||
# ui
|
||||
|
||||
@@ -283,7 +283,10 @@ fn start_el(e: &quick_xml::events::BytesStart) -> Result<El, String> {
|
||||
for a in e.attributes().with_checks(false) {
|
||||
let a = a.map_err(|e| e.to_string())?;
|
||||
let k = String::from_utf8_lossy(a.key.as_ref()).to_string();
|
||||
let v = a.unescape_value().map(|v| v.to_string()).unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string());
|
||||
let v = a
|
||||
.normalized_value(quick_xml::XmlVersion::Implicit1_0)
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|_| String::from_utf8_lossy(&a.value).to_string());
|
||||
el.attrs.push((k, v));
|
||||
}
|
||||
Ok(el)
|
||||
|
||||
@@ -68,7 +68,9 @@ pub(crate) fn parse(xml: &str) -> Result<El, ImportError> {
|
||||
attrs: e
|
||||
.attributes()
|
||||
.flatten()
|
||||
.map(|a| (local(a.key.as_ref()), a.unescape_value().map(|v| v.to_string()).unwrap_or_default()))
|
||||
.map(|a| {
|
||||
(local(a.key.as_ref()), a.normalized_value(quick_xml::XmlVersion::Implicit1_0).map(|v| v.to_string()).unwrap_or_default())
|
||||
})
|
||||
.collect(),
|
||||
kids: vec![],
|
||||
};
|
||||
@@ -80,7 +82,9 @@ pub(crate) fn parse(xml: &str) -> Result<El, ImportError> {
|
||||
attrs: e
|
||||
.attributes()
|
||||
.flatten()
|
||||
.map(|a| (local(a.key.as_ref()), a.unescape_value().map(|v| v.to_string()).unwrap_or_default()))
|
||||
.map(|a| {
|
||||
(local(a.key.as_ref()), a.normalized_value(quick_xml::XmlVersion::Implicit1_0).map(|v| v.to_string()).unwrap_or_default())
|
||||
})
|
||||
.collect(),
|
||||
kids: vec![],
|
||||
};
|
||||
@@ -792,4 +796,18 @@ mod tests {
|
||||
assert_eq!(i.story.paras[0].para.list_type, None);
|
||||
assert_eq!(i.warnings.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_element_with_many_attributes_parses_in_linear_time() {
|
||||
// RUSTSEC-2026-0194: before quick-xml 0.41 the duplicate-attribute check compared each name with every
|
||||
// earlier one on the element, so a crafted .docx/.xlsx with one huge tag hung the import (O(N²)).
|
||||
let attrs: String = (0..100_000).map(|i| format!(" w:a{i}=\"{i}\"")).collect();
|
||||
let xml = format!("<w:document><w:body><w:p{attrs}/></w:body></w:document>");
|
||||
let started = std::time::Instant::now();
|
||||
let doc = parse(&xml).unwrap();
|
||||
assert!(started.elapsed() < std::time::Duration::from_secs(5), "parse took {:?}", started.elapsed());
|
||||
let p = doc.child("body").and_then(|b| b.child("p")).unwrap();
|
||||
assert_eq!(p.attr("a0"), Some("0"));
|
||||
assert_eq!(p.attr("a99999"), Some("99999"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user